Init: bootstrap go module with basic framework

This commit is contained in:
2025-09-25 08:14:34 +08:00
commit 60f534be1e
47 changed files with 1084 additions and 0 deletions

84
cmd/backend.go Normal file
View File

@@ -0,0 +1,84 @@
package cmd
import (
"database/sql"
"log"
"net/http"
"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/service/amane-tanikaze-dcbot/amane/handlers/api"
_ "gitea.konchin.com/service/amane-tanikaze-dcbot/amane/handlers/docs"
"gitea.konchin.com/service/amane-tanikaze-dcbot/amane/middlewares"
"gitea.konchin.com/service/amane-tanikaze-dcbot/amane/tracing"
)
// @Title Amane Tanikaze Discord Bot Backend
// @Version 2.0-alpha1
// @TermsOfService http://swagger.io/terms/
// @License.Name 0BSD
// @BasePath /
var backendCmd = &cobra.Command{
Use: "backend",
Short: "backend server",
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
tracing.InitTracer()
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(
viper.GetString("pg-dsn"))))
db := bun.NewDB(sqldb, pgdialect.New())
db.AddQueryHook(bunotel.NewQueryHook(bunotel.WithDBName("PostgreSQL")))
router := bunrouter.New()
middlewaresHandlers := middlewares.NewHandlers(db)
backend := router.NewGroup("").
Use(middlewaresHandlers.ErrorHandler)
if viper.GetBool("swagger") {
backend.GET("/docs/*any",
bunrouter.HTTPHandlerFunc(httpSwagger.Handler()))
}
apiHandlers := api.NewHandlers(db)
apiGroup := backend.NewGroup("/api")
apiGroup.GET("/image",
apiHandlers.GetImage)
tracing.Logger.Ctx(ctx).
Info("http server up",
zap.String("http.port", viper.GetString("port")))
log.Println(http.ListenAndServe(":"+viper.GetString("port"),
otelhttp.NewHandler(router, "")))
},
}
func init() {
backendCmd.Flags().
String("port", "8080", "Port to listen on")
backendCmd.Flags().
String("pg-dsn",
"postgres://amane:amane@postgres:5432/amane?sslmode=disable",
"PostgreSQL connection string")
backendCmd.Flags().
Bool("zap-develop", false, "Enable development log")
backendCmd.Flags().
Bool("swagger", false, "Enable swagger")
}

7
cmd/dcbot.go Normal file
View File

@@ -0,0 +1,7 @@
package cmd
import "github.com/spf13/cobra"
var dcbotCmd = &cobra.Command{
Use: "dcbot",
}

15
cmd/migrates/init.go Normal file
View File

@@ -0,0 +1,15 @@
package migrates
import (
"github.com/spf13/cobra"
)
var initCmd = &cobra.Command{
Use: "init",
Short: "Initialize migration table",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
return migrator.Init(ctx)
},
}

13
cmd/migrates/lock.go Normal file
View File

@@ -0,0 +1,13 @@
package migrates
import (
"github.com/spf13/cobra"
)
var lockCmd = &cobra.Command{
Use: "lock",
Short: "Lock migrations",
RunE: func(cmd *cobra.Command, args []string) error {
return migrator.Lock(cmd.Context())
},
}

33
cmd/migrates/rollback.go Normal file
View File

@@ -0,0 +1,33 @@
package migrates
import (
"fmt"
"github.com/spf13/cobra"
)
var rollbackCmd = &cobra.Command{
Use: "rollback",
Short: "Rollback from last migration group",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
if err := migrator.Lock(ctx); err != nil {
return err
}
defer migrator.Unlock(ctx)
group, err := migrator.Rollback(ctx)
if err != nil {
return err
}
if group.IsZero() {
fmt.Printf("there are no groups to roll back\n")
return nil
}
fmt.Printf("roll back from %s\n", group)
return nil
},
}

44
cmd/migrates/root.go Normal file
View File

@@ -0,0 +1,44 @@
package migrates
import (
"database/sql"
"gitea.konchin.com/service/amane-tanikaze-dcbot/amane/migrations"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
"github.com/uptrace/bun/extra/bundebug"
"github.com/uptrace/bun/migrate"
)
var (
migrator *migrate.Migrator
db *bun.DB
)
var RootCmd = &cobra.Command{
Use: "migrate",
Short: "Migration related commands",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
sqldb := sql.OpenDB(pgdriver.NewConnector(
pgdriver.WithDSN(viper.GetString("pg-dsn"))))
db = bun.NewDB(sqldb, pgdialect.New())
db.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))
migrator = migrate.NewMigrator(db, migrations.Migrations)
},
}
func init() {
RootCmd.AddCommand(upCmd)
RootCmd.AddCommand(initCmd)
RootCmd.AddCommand(rollbackCmd)
RootCmd.AddCommand(lockCmd)
RootCmd.AddCommand(unlockCmd)
RootCmd.PersistentFlags().
String("pg-dsn",
"postgres://amane:amane@postgres:5432/amane?sslmode=disable",
"Postgres connection string")
}

11
cmd/migrates/unlock.go Normal file
View File

@@ -0,0 +1,11 @@
package migrates
import "github.com/spf13/cobra"
var unlockCmd = &cobra.Command{
Use: "unlock",
Short: "Unlock migrations",
RunE: func(cmd *cobra.Command, args []string) error {
return migrator.Unlock(cmd.Context())
},
}

33
cmd/migrates/up.go Normal file
View File

@@ -0,0 +1,33 @@
package migrates
import (
"fmt"
"github.com/spf13/cobra"
)
var upCmd = &cobra.Command{
Use: "up",
Short: "migrate up",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
if err := migrator.Lock(ctx); err != nil {
return err
}
defer migrator.Unlock(ctx)
group, err := migrator.Migrate(ctx)
if err != nil {
return err
}
if group.IsZero() {
fmt.Printf("there are no new migrations to run\n")
return nil
}
fmt.Printf("migrated to %s\n", group)
return nil
},
}

27
cmd/root.go Normal file
View File

@@ -0,0 +1,27 @@
package cmd
import (
"strings"
"gitea.konchin.com/service/amane-tanikaze-dcbot/amane/cmd/migrates"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var RootCmd = &cobra.Command{
Use: "amane",
Short: "Amane Tanikaze Discord Bot",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
viper.AutomaticEnv()
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.BindPFlags(cmd.PersistentFlags())
viper.BindPFlags(cmd.Flags())
},
}
func init() {
cobra.EnableTraverseRunHooks = true
RootCmd.AddCommand(dcbotCmd)
RootCmd.AddCommand(backendCmd)
RootCmd.AddCommand(migrates.RootCmd)
}