package worker import ( "context" "errors" "net" "net/http" "net/url" ) var ( UnsupportedSchemeErr = errors.New("Ivalid schema, only tcp and unix supported") ) type ServerTask struct { addr string handler http.Handler } func NewServerTask(addr string, handler http.Handler) *ServerTask { return &ServerTask{ addr: addr, handler: handler, } } func (s *ServerTask) Start(ctx context.Context) error { done := make(chan error) listen, err := getListen(s.addr) if err != nil { return err } server := &http.Server{ Handler: s.handler, } go func() { done <- server.Serve(listen) }() select { // if ListenAndServe error for something other than context.Canceled //(e.g.: address already in use) it trigger done to return sonner with // the return error case err := <-done: return err // in case of context canceled it will manually trigger the server to // shutdown, and return its error, which is most cases, but not limited, is // context.Canceled. case <-ctx.Done(): return server.Shutdown(ctx) } } func getListen(addr string) (net.Listener, error) { u, err := url.Parse(addr) if err != nil { return nil, err } switch u.Scheme { case "tcp": return net.Listen(u.Scheme, u.Host) case "unix": host, err := url.JoinPath("/", u.Host, u.Path) if err != nil { return nil, err } return net.Listen(u.Scheme, host) default: return nil, UnsupportedSchemeErr } }