package server import ( "context" "errors" "fmt" "net" "net/http" "os" "git.faercol.me/faercol/http-boot-server/bootserver/config" "github.com/sirupsen/logrus" ) type Server struct { ctx context.Context cancel context.CancelFunc httpSrv *http.Server listener net.Listener serverMode config.ListeningMode address string handler *http.ServeMux l *logrus.Logger } func newUnixListener(sockPath string) (net.Listener, error) { if err := os.Remove(sockPath); err != nil && !errors.Is(err, os.ErrNotExist) { return nil, fmt.Errorf("failed to cleanup previously existing socket: %w", err) } sock, err := net.Listen("unix", sockPath) if err != nil { return nil, fmt.Errorf("failed to create unix socket: %w", err) } if err := os.Chmod(sockPath, 0o777); err != nil { return nil, fmt.Errorf("failed to set permissions to unix socket: %w", err) } return sock, nil } func New(appConf *config.AppConfig, logger *logrus.Logger) (*Server, error) { var listener net.Listener var addr string var err error switch appConf.ServerMode { case config.ModeNet: addr = fmt.Sprintf("%s:%d", appConf.Host, appConf.Port) listener, err = net.Listen("tcp", addr) if err != nil { return nil, fmt.Errorf("failed to init server in net mode: %w", err) } case config.ModeUnix: addr = appConf.SockPath listener, err = newUnixListener(appConf.SockPath) if err != nil { return nil, fmt.Errorf("failed to init server in unix mode: %w", err) } default: panic(fmt.Errorf("unexpected listening mode %v", appConf.ServerMode)) } m := http.NewServeMux() return &Server{ handler: m, httpSrv: &http.Server{ Handler: m, }, listener: listener, l: logger, serverMode: appConf.ServerMode, address: addr, }, nil } func (s *Server) initMux() { s.handler.HandleFunc("/", s.statusHandler) } func (s *Server) Run(ctx context.Context) { s.ctx, s.cancel = context.WithCancel(ctx) s.initMux() switch s.serverMode { case config.ModeNet: s.l.Infof("Server listening on host %q", s.address) case config.ModeUnix: s.l.Infof("Server listening on unix socket %q", s.address) default: } if err := s.httpSrv.Serve(s.listener); err != nil { s.l.Errorf("failed to serve HTTP server: %s", err.Error()) } s.cancel() } func (s *Server) Done() <-chan struct{} { return s.ctx.Done() } func (s *Server) statusHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { w.WriteHeader(http.StatusMethodNotAllowed) return } w.Write([]byte("Hello world!")) }