package cmds import ( "database/sql" "log" "net/http" "gitea.konchin.com/go2025/backend/handlers/api" "gitea.konchin.com/go2025/backend/handlers/auth" "gitea.konchin.com/go2025/backend/handlers/img" "gitea.konchin.com/go2025/backend/implements" "gitea.konchin.com/go2025/backend/middlewares" "gitea.konchin.com/go2025/backend/tracing" "gitea.konchin.com/go2025/backend/utils" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/spf13/cobra" "github.com/spf13/viper" httpSwagger "github.com/swaggo/http-swagger" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/pgdialect" "github.com/uptrace/bun/driver/pgdriver" "github.com/uptrace/bun/extra/bunotel" "github.com/uptrace/bunrouter" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.uber.org/zap" _ "gitea.konchin.com/go2025/backend/docs" ) // @title Golang 2025 Final Project // @version 0.0.1 // @termsOfService http://swagger.io/terms // // @license.name 0BSD // @basePath / var serveCmd = &cobra.Command{ Use: "serve", Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() // Initialize tracing appname := "go2025-backend" tracing.InitTracer(appname) if viper.GetString("uptrace-dsn") != "" { tracing.InitUptrace(appname) defer tracing.DeferUptrace(ctx) } // Initialize DB instance sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN( viper.GetString("pg-connection-string")))) bunDB := bun.NewDB(sqldb, pgdialect.New()) bunDB.AddQueryHook(bunotel.NewQueryHook(bunotel.WithDBName("backend"))) if err := utils.InitDB(ctx, bunDB); err != nil { tracing.Logger.Ctx(ctx). Panic("failed to init database", zap.Error(err)) panic(err) } // Initialize MinIO instance mc, err := minio.New(viper.GetString("minio-host"), &minio.Options{ Creds: credentials.NewStaticV4( viper.GetString("minio-accesskey"), viper.GetString("minio-secretkey"), "", ), Secure: viper.GetBool("minio-usessl"), }) if err != nil { tracing.Logger.Ctx(ctx). Error("failed to create minio client", zap.Error(err)) panic(err) } if err := utils.InitMinIO(ctx, mc); err != nil { tracing.Logger.Ctx(ctx). Error("failed to minio init", zap.Error(err)) panic(err) } // Initialize custom interfaces db := implements.NewBunDatabase(bunDB) s3 := implements.NewMinIOObjectStorage(mc) // Initialize handlers midHandlers := middlewares.NewHandlers(db) apis := api.NewHandlers(db, s3) auths := auth.NewHandlers(db) imgs := img.NewHandlers(s3) // Initialize backend router router := bunrouter.New() backend := router.NewGroup(""). Use(middlewares.ErrorHandler). Use(middlewares.BunrouterOtel). Use(middlewares.AccessLog). Use(middlewares.CORSHandler) backend.OPTIONS("/*any", utils.GetHealthz) backend.GET("/healthz", utils.GetHealthz) apiGroup := backend.NewGroup("/api"). Use(midHandlers.CheckRefreshToken). Use(midHandlers.CheckAccessToken) apiGroup.DELETE("/alias/:id", apis.DeleteAlias) apiGroup.DELETE("/image/:id", apis.DeleteImage) apiGroup.GET("/aliases", apis.GetAliases) apiGroup.GET("/images", apis.GetImages) apiGroup.POST("/image", apis.PostImage) apiGroup.PUT("/image/:id/aliases", apis.PutImageAliases) authGroup := backend.NewGroup("/auth") authGroup.POST("/login", auths.PostLogin) authGroup.POST("/gen-login-url", midHandlers.CheckPresharedKey(auths.PostGenLoginUrl)) imgGroup := backend.NewGroup("/img") imgGroup.GET("/:filename", imgs.Get) if viper.GetBool("swagger") { backend.GET("/swagger/*any", bunrouter.HTTPHandlerFunc( httpSwagger.Handler())) } log.Println(http.ListenAndServe( ":"+viper.GetString("port"), otelhttp.NewHandler(router, ""))) }, } func init() { serveCmd.Flags(). String("port", "8080", "Port to listen on") serveCmd.Flags(). Bool("https", false, "Enable https mode") serveCmd.Flags(). String("external-url", "http://localhost:8080", "External url for login") serveCmd.Flags(). String("cors-origin", "", "CORS origin") serveCmd.Flags(). String("preshared-key", "poop", "Preshared key for Discord Bot") serveCmd.Flags(). Bool("reset", false, "Reset database") serveCmd.Flags(). Int64("access-token-timeout", 300, "Timeout of Access Token JWT") serveCmd.Flags(). String("access-token-secret", "poop", "Access Token JWT HMAC secret") serveCmd.Flags(). Int64("refresh-token-timeout", 3600, "Timeout of Refresh Token JWT") serveCmd.Flags(). String("refresh-token-secret", "poop", "Refresh Token JWT HMAC secret") serveCmd.Flags(). Bool("zap-production", true, "Toggle production log format") serveCmd.Flags(). Bool("swagger", false, "Toggle swagger") serveCmd.Flags(). String("pg-connection-string", "postgres://go2025:go2025@postgres:5432/go2025?sslmode=disable", "Postgres connection string") serveCmd.Flags(). String("minio-host", "minio:9000", "MinIO host[:port]") serveCmd.Flags(). String("minio-bucket", "go2025", "MinIO bucket") serveCmd.Flags(). String("minio-accesskey", "poop", "MinIO accesskey") serveCmd.Flags(). String("minio-secretkey", "poop114514", "MinIO secretkey") serveCmd.Flags(). Bool("minio-usessl", false, "MinIO usessl") serveCmd.Flags(). String("uptrace-dsn", "", "Uptrace DSN (disabled by default)") }