package main import ( "context" "crypto/tls" "errors" "flag" "fmt" "log/slog" "net" "os" "os/signal" "syscall" "time" "github.com/gofiber/fiber/v3" ) func run(ctx context.Context, path string) error { config, err := loadStartup(path) if err != nil { return err } data, err := loadSnapshots(config.Snapshots, config.DispatcherID) if err != nil { return err } slog.Info("test configurations loaded", "dispatcher_id", data.dispatcherID, "tasks", len(data.tasks)) if err = os.MkdirAll(config.Feedback, 0700); err != nil { return fmt.Errorf("create private feedback directory: %w", err) } info, err := os.Stat(config.Feedback) if err != nil { return err } if !info.IsDir() || info.Mode().Perm()&0077 != 0 { return errors.New("feedback directory must be private") } b, err := connectBroker(config.BrokerURL, data) if err != nil { return err } defer b.conn.Close() slog.Info("isolated MQ topology ready", "dispatcher_id", data.dispatcherID) listener, err := net.Listen("tcp", config.Listen) if err != nil { return fmt.Errorf("listen: %w", err) } defer listener.Close() if config.TLSCert != "" { pair, e := tls.LoadX509KeyPair(config.TLSCert, config.TLSKey) if e != nil { return fmt.Errorf("load configured TLS pair: %w", e) } listener = tls.NewListener(listener, &tls.Config{Certificates: []tls.Certificate{pair}, MinVersion: tls.VersionTLS12}) } s := newService(data, config.DispatcherSecret) s.feedbackDir = config.Feedback s.publish = b.publish child, cancel := context.WithCancel(ctx) defer cancel() errs := make(chan error, 2) go func() { errs <- b.consume(child, s) }() go func() { errs <- s.app.Listener(listener, fiber.ListenConfig{DisableStartupMessage: true}) }() slog.Info("SaaS test server listening", "address", listener.Addr().String(), "tls", config.TLSCert != "", "automatic_commands", false) select { case <-ctx.Done(): err = nil case err = <-errs: if err == nil && ctx.Err() == nil { err = errors.New("SaaS test server stopped unexpectedly") } } cancel() if shutdownErr := s.app.ShutdownWithTimeout(5 * time.Second); shutdownErr != nil { err = errors.Join(err, fmt.Errorf("HTTP shutdown: %w", shutdownErr)) } // Closing the listener/connection unblocks both workers; do not leave consumers behind. listener.Close() b.conn.Close() slog.Info("SaaS test server stopped") return err } func main() { var path string flag.StringVar(&path, "config", "", "private startup JSON (required)") flag.Parse() if path == "" || flag.NArg() != 0 { fmt.Fprintln(os.Stderr, "usage: saas-server --config /path/server.json") os.Exit(2) } ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer cancel() if err := run(ctx, path); err != nil { slog.Error("SaaS test server failed", "error", err) os.Exit(1) } }