cerrado @ master

 1package worker
 2
 3import (
 4	"context"
 5	"errors"
 6	"log/slog"
 7	"net"
 8	"net/http"
 9	"net/url"
10)
11
12var (
13	ErrUnsupportedScheme = errors.New("Ivalid schema, only tcp and unix supported")
14)
15
16type ServerTask struct {
17	addr    string
18	handler http.Handler
19}
20
21func NewServerTask(addr string, handler http.Handler) *ServerTask {
22	return &ServerTask{
23		addr:    addr,
24		handler: handler,
25	}
26}
27
28func (s *ServerTask) Start(ctx context.Context) error {
29	done := make(chan error)
30
31	listen, err := getListen(s.addr)
32	if err != nil {
33		return err
34	}
35	server := &http.Server{
36		Handler: s.handler,
37	}
38
39	go func() {
40		slog.Info("Serving", "addr", listen.Addr().String(), "network", listen.Addr().Network())
41		done <- server.Serve(listen)
42	}()
43
44	select {
45	// if ListenAndServe error for something other than context.Canceled
46	//(e.g.: address already in use) it trigger done to return sonner with
47	// the return error
48	case err := <-done:
49		return err
50
51	// in case of context canceled it will manually trigger the server to
52	// shutdown, and return its error, which is most cases, but not limited, is
53	// context.Canceled.
54	case <-ctx.Done():
55		return server.Shutdown(ctx)
56	}
57}
58
59func getListen(addr string) (net.Listener, error) {
60	u, err := url.Parse(addr)
61	if err != nil {
62		return nil, err
63	}
64
65	switch u.Scheme {
66	case "tcp":
67		return net.Listen(u.Scheme, u.Host)
68	case "unix":
69		host, err := url.JoinPath("/", u.Host, u.Path)
70		if err != nil {
71			return nil, err
72		}
73		return net.Listen(u.Scheme, host)
74	default:
75		return nil, ErrUnsupportedScheme
76	}
77}