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}