// Package main is the entry point for the pixad image proxy server. package main import ( "context" "fmt" "os" "os/signal" "syscall" "github.com/spf13/cobra" "go.uber.org/fx" "sneak.berlin/go/pixa/internal/config" "sneak.berlin/go/pixa/internal/database" "sneak.berlin/go/pixa/internal/globals" "sneak.berlin/go/pixa/internal/handlers" "sneak.berlin/go/pixa/internal/healthcheck" "sneak.berlin/go/pixa/internal/logger" "sneak.berlin/go/pixa/internal/middleware" "sneak.berlin/go/pixa/internal/server" ) var Version string //nolint:gochecknoglobals // set by ldflags var configPath string //nolint:gochecknoglobals // cobra flag func main() { rootCmd := &cobra.Command{ Use: "pixad", Short: "Pixa image caching proxy server", Run: run, } rootCmd.Flags().StringVarP(&configPath, "config", "c", "", "path to config file") err := rootCmd.Execute() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func run(_ *cobra.Command, _ []string) { globals.Version = Version // Set config path in environment if specified via flag if configPath != "" { _ = os.Setenv("PIXA_CONFIG_PATH", configPath) } // A write to a closed stdout or stderr must not end the process. signal.Ignore(syscall.SIGPIPE) app := fx.New( fx.Provide( config.New, database.New, globals.New, handlers.New, logger.New, server.New, middleware.New, healthcheck.New, ), fx.Invoke( func(log *logger.Logger) { log.Identify() }, func(*server.Server) {}, ), ) os.Exit(runApp(app)) } // runApp starts app, waits for SIGINT, SIGTERM or a shutdown request, then // stops app. It returns the exit code: the one the shutdown request carries, // 0 for a signal, or 1 when app fails to start or to stop; fx logs that // error itself. It does what fx's App.Run does, but returns the exit code // instead of exiting. func runApp(app *fx.App) int { startCtx, cancelStart := context.WithTimeout( context.Background(), app.StartTimeout()) defer cancelStart() err := app.Start(startCtx) if err != nil { return 1 } shutdown := <-app.Wait() stopCtx, cancelStop := context.WithTimeout( context.Background(), app.StopTimeout()) defer cancelStop() err = app.Stop(stopCtx) if err != nil { return 1 } return shutdown.ExitCode }