Files
backend/cmds/serve.go
Yi-Ting Shih 1cf3a9ef0b
All checks were successful
Go test / run-go-vet (push) Successful in 6s
Go test / check-swagger-up-to-date (push) Successful in 10s
Go test / run-go-test (push) Successful in 36s
Go test / cleanup-go-test (push) Successful in 14s
Go test / release-image (push) Successful in 3m20s
Fix: cookie timeout
2025-12-12 02:09:46 +08:00

182 lines
5.2 KiB
Go

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().
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)")
}