package main import ( "context" "fmt" "log/slog" "net/http" "os" "time" "forgejo.merr.is/annika/isl-api/controllers" "forgejo.merr.is/annika/isl-api/middlewares" "forgejo.merr.is/annika/isl-api/routes" "forgejo.merr.is/annika/isl-api/services" "forgejo.merr.is/annika/isl-api/sql/powerItem" "github.com/go-chi/chi/v5" "github.com/go-chi/cors" "github.com/go-chi/httplog/v2" "github.com/jackc/pgx/v4/pgxpool" "github.com/lmittmann/tint" "github.com/spf13/viper" ) var conf *EnvConfigs var logger *slog.Logger func init() { w := os.Stderr logger = slog.New( tint.NewHandler(w, &tint.Options{ TimeFormat: time.RFC3339Nano, }), ) logger.Info("Initializing isl-api") setupConfig() logger = slog.New( tint.NewHandler(w, &tint.Options{ Level: conf.GetLogLevel(), TimeFormat: time.RFC3339Nano, }), ) } func main() { logger.Info("Starting isl-api") deps := dependencies{} deps.initializeDependencies() logger.Info(fmt.Sprintf("Preparing to listen on `:%v`", conf.HttpPort)) err := http.ListenAndServe(fmt.Sprintf(":%v", conf.HttpPort), deps.router) logger.Error("Error starting server", "error", err) } func setupConfig() { logger.Info("Loading config") viper.AddConfigPath(".") viper.SetConfigName(".env") viper.SetConfigType("env") viper.SetEnvPrefix("isl_api") viper.AutomaticEnv() if err := viper.ReadInConfig(); err != nil { logger.Error("Error reading env file, exiting", "error", err) panic(err) } if err := viper.Unmarshal(&conf); err != nil { logger.Error("Unable to unmarshal configuration, exiting", "error", err) panic(err) } logger.Info("Finished loading config") } type dependencies struct { router *chi.Mux postgresConnection *pgxpool.Pool context context.Context powerItemQuerier *powerItem.DBQuerier powerItemService *services.PowerItemService powerItemController *controllers.PowerItemController } func (d *dependencies) initializeDependencies() error { logger.Info("Initializing dependencies") var err error d.router = chi.NewRouter() httpLogger := httplog.NewLogger("isl-api", httplog.Options{ Concise: true, RequestHeaders: true, }) httpLogger.Logger = logger d.router.Use(httplog.RequestLogger(httpLogger)) d.router.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Cache-Control", "Expires", "Pragma"}, })) d.context = context.Background() d.postgresConnection, err = pgxpool.Connect(d.context, conf.ConnectionString) if err != nil { logger.Error("Error setting up database connection", "error", err) return err } d.powerItemQuerier = powerItem.NewQuerier(d.postgresConnection) d.powerItemService = services.NewPowerItemService(d.powerItemQuerier) d.powerItemController = controllers.NewPowerItemController(d.powerItemService) tokenAuth, err := middlewares.New(conf.JWKSURI, d.context) if err != nil { logger.Error("Error setting up JWT authentication middleware", "error", err) } d.router.Mount("/powerItems", routes.SetupPowerItemRoutes(*d.powerItemController, tokenAuth)) logger.Info("Finished initializing dependencies") return nil }