Files
preface-tools/internal/app/app.go
T
2026-07-13 01:26:49 +08:00

70 lines
2.1 KiB
Go

package app
import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"git.michelsen.id/phill/preface-tools/internal/auth"
"git.michelsen.id/phill/preface-tools/internal/httpserver"
"git.michelsen.id/phill/preface-tools/internal/tools"
"git.michelsen.id/phill/preface-tools/internal/tools/comicanimator"
)
func Run() error {
cfg, err := LoadConfigFromEnv()
if err != nil {
return err
}
comicCfg, err := comicanimator.LoadConfigFromEnv()
if err != nil {
return err
}
var level slog.Level
if err := level.UnmarshalText([]byte(cfg.LogLevel)); err != nil {
return fmt.Errorf("invalid LOG_LEVEL %q: %w", cfg.LogLevel, err)
}
handlerOptions := &slog.HandlerOptions{Level: level}
var handler slog.Handler = slog.NewTextHandler(os.Stdout, handlerOptions)
if cfg.LogFormat == "json" {
handler = slog.NewJSONHandler(os.Stdout, handlerOptions)
}
log := slog.New(handler)
a := auth.New(cfg.StudentPIN, cfg.InstructorPIN, cfg.SessionSecret, cfg.SessionDuration, cfg.Environment == "production")
comic, err := comicanimator.New(comicCfg, log, a)
if err != nil {
return err
}
registry := tools.NewRegistry()
if err = registry.Register(comic); err != nil {
return err
}
srv := &http.Server{Addr: cfg.Address, Handler: httpserver.New(a, registry, log).Handler(), ReadHeaderTimeout: cfg.ReadHeaderTimeout, ReadTimeout: cfg.ReadTimeout, WriteTimeout: cfg.WriteTimeout, IdleTimeout: cfg.IdleTimeout, MaxHeaderBytes: 64 << 10}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
workerDone := make(chan error, 1)
go func() { workerDone <- comic.Run(ctx) }()
serverDone := make(chan error, 1)
go func() { log.Info("server starting", "address", cfg.Address); serverDone <- srv.ListenAndServe() }()
select {
case err = <-serverDone:
if !errors.Is(err, http.ErrServerClosed) {
stop()
return err
}
case <-ctx.Done():
}
shutdownCtx, cancel := context.WithTimeout(context.Background(), cfg.ShutdownTimeout)
defer cancel()
if err := srv.Shutdown(shutdownCtx); err != nil {
return err
}
stop()
return <-workerDone
}