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