package app import ( "context" "errors" "fmt" "log" "net/http" "time" "supervisor/internal/config" "supervisor/internal/httpserver" "supervisor/internal/session" "supervisor/internal/store/memory" "supervisor/internal/supervisor" "supervisor/internal/util" ) type App struct { cfg config.Config logger *log.Logger httpServer *http.Server SessionManager *session.Manager Supervisor *supervisor.Manager } func New(cfg config.Config) (*App, error) { logger := util.NewLogger() memStore := memory.NewStore() sessionManager := session.NewManager(memStore, nil) supervisorManager := supervisor.NewManager() router, err := httpserver.NewRouter(httpserver.Dependencies{ Logger: logger, Manager: sessionManager, }) if err != nil { return nil, fmt.Errorf("build router: %w", err) } srv := &http.Server{ Addr: cfg.Addr, Handler: router, ReadHeaderTimeout: 10 * time.Second, } return &App{ cfg: cfg, logger: logger, httpServer: srv, SessionManager: sessionManager, Supervisor: supervisorManager, }, nil } func (a *App) Run(ctx context.Context) error { errCh := make(chan error, 1) go func() { a.logger.Printf("HTTP server listening on %s", a.cfg.Addr) errCh <- a.httpServer.ListenAndServe() }() select { case <-ctx.Done(): shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() _ = a.httpServer.Shutdown(shutdownCtx) return nil case err := <-errCh: if errors.Is(err, http.ErrServerClosed) { return nil } return err } }