package main import ( "context" "flag" "log/slog" "os" "os/signal" "syscall" "time" "arcline-email/config" ) func main() { cfgPath := flag.String("config", "arcline-email.toml", "path to config file") flag.Parse() cfg, err := config.Load(*cfgPath) if err != nil { slog.Error("failed to load config", "err", err) os.Exit(1) } logger := newLogger(cfg.Logging) slog.SetDefault(logger) slog.Info("arcline-email starting", "hostname", cfg.Server.Hostname) // TODO: initialize and start servers (SMTP, IMAP) ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() <-ctx.Done() slog.Info("shutdown signal received") stop() // release signal resources before shutdown shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // TODO: call server.Shutdown(shutdownCtx) for each listener _ = shutdownCtx slog.Info("shutdown complete") } func newLogger(cfg config.LoggingConfig) *slog.Logger { var level slog.Level if err := level.UnmarshalText([]byte(cfg.Level)); err != nil { level = slog.LevelInfo } opts := &slog.HandlerOptions{Level: level} if cfg.Format == "text" { return slog.New(slog.NewTextHandler(os.Stdout, opts)) } return slog.New(slog.NewJSONHandler(os.Stdout, opts)) }