-
-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Customizable net.Listener for advanced use cases, such as tunneling #245
base: main
Are you sure you want to change the base?
Conversation
Ignaciojeria
commented
Nov 30, 2024
No test added? |
Would you mind following the |
Also we have two entrypoints Also maybe a refactor is in order within the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot, good idea!
If you can make the requested changes, it would be nice.
Pardon me. I was on a phone so I was short. I will say this is a great contribution. I hope you’re enjoying fuego. 😄 |
I've addressed some of the suggestions and pushed a new change. I haven't had the chance to fully test it yet, but I'll be running some tests soon. Any feedback is greatly appreciated! |
serve.go
Outdated
if err := s.setupDefaultListener(); err != nil { | ||
return fmt.Errorf("failed to start server: %w", err) | ||
} | ||
s.setup() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setup listener is now called before setup, at all place setup is called if I'm not wrong
What about calling it in setup, and update setup signature to return an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Two heads are better than one. I made some adjustments and have been running manual tests (locally only).
serve.go
Outdated
if err := s.setup(certFile, keyFile); err != nil { | ||
return err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you call WithTLSListener here?
It would allow to pass certFile and keyFile to setup, and the check on isTLS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code was significantly simplified based on the observation. Can you help check if there’s any room for improvement? Thank you very much!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great.
I'll open a PR to your fork
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened Ignaciojeria#1
serve.go
Outdated
@@ -100,7 +100,7 @@ func (s *Server) setupDefaultListener() error { | |||
} | |||
addr := s.Server.Addr | |||
if addr == "" { | |||
addr = "127.0.0.1:9999" | |||
addr = ":9999" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please check TestPetstoreOpenAPIGeneration
it seems broken now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i will check now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did it in Ignaciojeria#1
But let me ask you the question here.
Why did you remove the local host? To listen on all interfaces?
Was this changes needed in this exact PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I maintained localhost as the default to preserve the original implementation
I'm not a fuego maintainer I opened Please consider it. |
server.go
Outdated
func getServerAddress(s *Server) string { | ||
if s.Listener != nil { | ||
return s.Listener.Addr().String() | ||
} | ||
if s.Server.Addr != "" { | ||
return s.Server.Addr | ||
} | ||
// Default address if none is set | ||
return ":9999" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no reason for this method.
setListener now sets s.Server.Addr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function removed
server.go
Outdated
@@ -68,6 +70,8 @@ type Server struct { | |||
|
|||
OpenApiSpec openapi3.T // OpenAPI spec generated by the server | |||
|
|||
Listener net.Listener |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are adding a listener
So it should be closed when server stops
So please add this
func (s *Server) Close () {
if s.Listener != nil }
s.Listener.Close()
}
s.Server.Close()
return
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method added
server.go
Outdated
@@ -68,6 +70,8 @@ type Server struct { | |||
|
|||
OpenApiSpec openapi3.T // OpenAPI spec generated by the server | |||
|
|||
Listener net.Listener |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a need for the listener to be public, you added WithListener
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are right now is private
server.go
Outdated
@@ -125,7 +129,6 @@ func NewServer(options ...func(*Server)) *Server { | |||
} | |||
|
|||
defaultOptions := [...]func(*Server){ | |||
WithAddr("localhost:9999"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a problem with this.
Please take a look at the PR I opened in your fork
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR merged. I removed WithTLSListener because it added unnecessary complexity. I believe RunTLS and WithListener already provide the user with the necessary customization options. Please correct me if I’m wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the same. 👍
Also, semantically, I was annoyed that WithTLSListener was not allowing to pass a listener
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused on why this is a problem?
server.go
Outdated
// WithListener configures the server to use a custom listener. | ||
// If no listener is provided, it creates a default listener using the server's address. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// WithListener configures the server to use a custom listener. | |
// If no listener is provided, it creates a default listener using the server's address. | |
// WithListener configures the server to use a custom listener. |
The sentence is no longer valid, as it raises a panic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sentence removed
server.go
Outdated
func WithListener(listener net.Listener) func(*Server) { | ||
return func(s *Server) { | ||
if s.listener != nil { | ||
panic("a listener is already configured; cannot overwrite it") | ||
} | ||
s.listener = listener | ||
s.Server.Addr = listener.Addr().String() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check, but I think there is a need for something like this
func WithListener(listener net.Listener) func(*Server) { | |
return func(s *Server) { | |
if s.listener != nil { | |
panic("a listener is already configured; cannot overwrite it") | |
} | |
s.listener = listener | |
s.Server.Addr = listener.Addr().String() | |
} | |
} | |
func WithListener(listener net.Listener) func(*Server) { | |
return func(s *Server) { | |
if s.listener != nil { | |
panic("a listener is already configured; cannot overwrite it") | |
} | |
s.listener = listener | |
if _, ok := listener.(tls.Listener) { | |
t.isTLS = true | |
} | |
s.Server.Addr = listener.Addr().String() | |
} | |
} |
This is pseudo code made on my phone, you may need to adapt/fix it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used reflection to check if the instance is of type tls.listener
// WithListener configures the server to use a custom listener.
func WithListener(listener net.Listener) func(*Server) {
return func(s *Server) {
if s.listener != nil {
panic("a listener is already configured; cannot overwrite it")
}
s.isTLS = isTLSListener(listener)
WithAddr(listener.Addr().String())(s)
s.listener = listener
}
}
func isTLSListener(listener net.Listener) bool {
listenerType := reflect.TypeOf(listener)
if listenerType != nil && listenerType.String() == "*tls.listener" {
return true
}
return false
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is way better, but using assertion seems overkill, also it's very slow.
server.go
Outdated
s.OpenApiSpec.Servers = append(s.OpenApiSpec.Servers, &openapi3.Server{ | ||
URL: "http://" + s.Addr, | ||
URL: "http://" + s.Server.Addr, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it be https:// when isTLS is true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, i get protocol from proto() method
server.go
Outdated
func isTLSListener(listener net.Listener) bool { | ||
listenerType := reflect.TypeOf(listener) | ||
if listenerType != nil && listenerType.String() == "*tls.listener" { | ||
return true | ||
} | ||
return false | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reflexion is slow, can't you use a type assertion?
server.go
Outdated
func WithListener(listener net.Listener) func(*Server) { | ||
return func(s *Server) { | ||
if s.listener != nil { | ||
panic("a listener is already configured; cannot overwrite it") | ||
} | ||
s.listener = listener | ||
s.Server.Addr = listener.Addr().String() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is way better, but using assertion seems overkill, also it's very slow.
To handle the overwriting of the listener or address, I have three options in mind:
What do you think is the best option, or do you have any suggestions? |
I would say no with the last option, it hides things. People may never calls it. Throwing a panic is not my favorite either, but why not. But first, why is there a problem to overload the listener if the server is not started? Why not checking if the server is started to raise panic instead of checking s.listener ? I mean for me there is the exact same issue with WithPort or WithAddress, you can overload until you started the server. Another option would have been to use Option patrern that supports errors handling, but it's a bit late maybe. But maybe it was what you were suggesting with option 2, add an errServe to the struct, set in on error, check it after the for opt loop. |
I also don't understand the checking around Addr. The default listener should should be created with whatever value |
server.go
Outdated
s.OpenApiSpec.Servers = append(s.OpenApiSpec.Servers, &openapi3.Server{ | ||
URL: "http://" + s.Addr, | ||
URL: fmt.Sprintf("%s://%s", s.proto(), s.Server.Addr), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this would always be just http at this point except in the case where a Listener is passed. The current behavior is that we don’t know until the user calls RunTLS which is fine.
I think we’d need even an even larger refactor to address this well. This falls out of scope of this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm. Actually probably the proper places is at the end of setup().
I could be wrong it’s late 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I thought it could be a problem too.
So does it have to be merged like that? With somehow a bug?
Or the refactoring should gf done before? Either here or in another PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing it in setup now is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last bit would be nice as it would setup the server stuff well. Also not sure why we need to know if the listener is TLS or not care to explain?
All in all thank you for the work. This PR was challenging and it didn't fit quite well into the patterns we've been sticking too but this looks good. 😄
It would be nice to have bit of organized commit history as I'm fan of commits being a body of work. We don't really have anything around here for commit guidelines yet so feel free to do as you wish unless someone expresses their opinions.
Thanks again
I removed the method that checks if the listener is TLS. Sorry if my commits are chaotic; I’m still learning. What do you think about canceling this pull request? I could create a new fork and consolidate all the changes into a single commit. |
It's OK, really.
I would say keep the PR, it can be squashed in a single commit once merged. If you still want to do it by your own, you can use But, from my perspective. It's better to have the history of changes in a PR than having it left behind, then another "clean but useless" one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, git rebase -i HEAD~<number>
is a great tool. I use it pretty much everyday.
Anywho, great work. It's awesome that you're learning by contributing to open source. I found that helped me more than anything.
Cheers!
Thank you for the contribution. Seems you need to |
I still have pending unit tests as adding a couple of lines caused the coverage to drop. I'll review it more thoroughly this week after work. |
server.go
Outdated
addr := s.Addr | ||
if s.listener != nil { | ||
addr = s.listener.Addr().String() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless, isn't it? Can't we directly use s.Addr
as it has been set in WithListener
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible for the user to do something poor here say the user adds their own listener and then their own withaddr. The value could be off since listener trumps everything. I plan on getting rid of this possibility with #248. Basically pushing the openapi server setup as close to startup as we can.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. Good thing mux and server are decorrelated in the std lib
…lidate if listenner is tls using reflection
…ener when listener != nil
Hey @Ignaciojeria, I added the tests and did come cleanup. I am gonna need you to rebase or you main branch though. (The rebase isn't the most fun either I just went through 😅). Here is the PR: Ignaciojeria#2 the two commits i added are: I also could just open the PR myself. Idk whatever you want to do. |
hmm. It seems all commits are duplicated. Did you rebase locally? |
Let me clean this up and push the updated branch |
Hey any update on this? 😄 |
@EwenQuim when we go on this flurry of merges I think we should pull this over the line first. |
…lid address in withTls gosum included Update all .mod files instead of only with-listener
@EwenQuim bump on this. I’ve added commits so I don’t like to approve my own work. |