package server import ( "context" "errors" "fmt" "net" "net/http" "os" "git.faercol.me/faercol/http-boot-server/bootserver/bootoption" "git.faercol.me/faercol/http-boot-server/bootserver/config" "git.faercol.me/faercol/http-boot-server/bootserver/controllers/client" "git.faercol.me/faercol/http-boot-server/bootserver/controllers/ui" "git.faercol.me/faercol/http-boot-server/bootserver/middlewares" "git.faercol.me/faercol/http-boot-server/bootserver/services" "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 clients map[string]bootoption.Client controllers map[string]http.Handler } 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)) } service := services.NewClientHandlerService(appConf.DataFilepath, logger) controllers := map[string]http.Handler{ client.EnrollRoute: middlewares.WithLogger(client.NewEnrollController(logger, service, appConf.UDPPort, appConf.UPDMcastGroup), logger), client.ConfigRoute: middlewares.WithLogger(client.NewGetConfigController(logger, service, appConf), logger), client.SetBootRoute: middlewares.WithLogger(client.NewBootController(logger, service), logger), ui.StaticRoute: middlewares.WithLogger(ui.NewStaticController(appConf.StaticDir), logger), ui.UIRoute: middlewares.WithLogger(ui.NewUIController(logger, service, appConf.StaticDir), logger), } m := http.NewServeMux() return &Server{ handler: m, httpSrv: &http.Server{ Handler: m, }, listener: listener, l: logger, serverMode: appConf.ServerMode, address: addr, clients: make(map[string]bootoption.Client), controllers: controllers, ctx: context.TODO(), }, nil } func (s *Server) initMux() { for r, c := range s.controllers { s.handler.Handle(r, c) } } 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() }