refactor(cfg): Restructure database configuration and initialization flow

- Replace separate DB/DSN fields with unified config.Database struct
    - Remove cfg/db.go and move DB client to config.Database.Client()
    - Update auth to use event-driven initialization via vb.init.auth event
    - Refactor models initialization to use event system (vb.init.settings/oauth/admin)
    - Update CLI to use event.Start() instead of manual InitDB() call
    - Fix auth_test.go to use new DB config structure
    - Update agents.md documentation with new CLI flags format
master
veypi 1 week ago
parent 23c7f6cb7a
commit 4a57017067

@ -11,8 +11,8 @@
```bash ```bash
//重置数据库 //重置数据库
rm /tmp/vb.sqlite && go run cli/main.go -db=sqlit -dsn /tmp/vb.sqlite db migrate rm /tmp/vb.sqlite
go run cli/main.go -db=sqlit -dsn /tmp/vb.sqlite -p 4000 go run cli/main.go -db.type=sqlite -db.dsn /tmp/vb.sqlite -p 4000
``` ```
可以通过 <http://localhost:4000/\_api.json> 查看接口列表 可以通过 <http://localhost:4000/\_api.json> 查看接口列表

@ -17,6 +17,7 @@ import (
"github.com/veypi/vbase/libs/cache" "github.com/veypi/vbase/libs/cache"
"github.com/veypi/vbase/models" "github.com/veypi/vbase/models"
"github.com/veypi/vigo" "github.com/veypi/vigo"
"github.com/veypi/vigo/contrib/event"
) )
// Auth 权限管理接口 // Auth 权限管理接口
@ -91,6 +92,10 @@ func init() {
"oauth-client:update", "oauth-client:update",
"oauth-client:delete", "oauth-client:delete",
) )
// 注册权限初始化回调到 cfg 包
// 这样 models.InitDB() 可以在合适的时机调用,避免循环依赖
event.Add("vb.init.auth", Factory.init)
} }
type authFactory struct { type authFactory struct {

@ -14,8 +14,8 @@ import (
// setupTestDB 初始化测试数据库 // setupTestDB 初始化测试数据库
func setupTestDB() { func setupTestDB() {
// 使用 SQLite 内存模式 // 使用 SQLite 内存模式
cfg.Config.DB = "sqlite" cfg.Config.DB.Type = "sqlite"
cfg.Config.DSN = fmt.Sprintf("file::memory:?cache=shared&_time=%d", time.Now().UnixNano()) cfg.Config.DB.Type = fmt.Sprintf("file::memory:?cache=shared&_time=%d", time.Now().UnixNano())
// 初始化数据库表 // 初始化数据库表
if err := models.AllModels.AutoMigrate(cfg.DB()); err != nil { if err := models.AllModels.AutoMigrate(cfg.DB()); err != nil {

@ -19,8 +19,7 @@ import (
// Options 本地配置选项(启动时加载,修改需重启) // Options 本地配置选项(启动时加载,修改需重启)
type Options struct { type Options struct {
// === 基础设施(必须)=== // === 基础设施(必须)===
DSN string `json:"dsn" usage:"数据库连接字符串"` // Data Source Name DB config.Database `json:"db"`
DB string `json:"db" usage:"数据库类型: mysql, postgres, sqlite"`
Redis config.Redis `json:"redis" usage:"Redis 配置addr: memory 使用内存模式"` Redis config.Redis `json:"redis" usage:"Redis 配置addr: memory 使用内存模式"`
Key config.Key `json:"key" usage:"系统密钥,用于加密敏感数据(建议 32 位以上)"` Key config.Key `json:"key" usage:"系统密钥,用于加密敏感数据(建议 32 位以上)"`
@ -53,8 +52,10 @@ type InitAdminConfig struct {
// Config 全局配置实例 // Config 全局配置实例
var Config = &Options{ var Config = &Options{
DB: "mysql", DB: config.Database{
Type: "mysql",
DSN: "root:123456@tcp(127.0.0.1:3306)/vbase?charset=utf8&parseTime=True&loc=Local", DSN: "root:123456@tcp(127.0.0.1:3306)/vbase?charset=utf8&parseTime=True&loc=Local",
},
Redis: config.Redis{ Redis: config.Redis{
Addr: "memory", Addr: "memory",
}, },
@ -72,3 +73,5 @@ var Config = &Options{
Email: "admin@example.com", Email: "admin@example.com",
}, },
} }
var DB = Config.DB.Client

@ -1,41 +0,0 @@
//
// db.go
// Copyright (C) 2024 veypi <i@veypi.com>
// 2025-03-04 16:08:06
// Distributed under terms of the MIT license.
//
package cfg
import (
"github.com/glebarez/sqlite"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var db *gorm.DB
func DB() *gorm.DB {
if db == nil {
var err error
var conn gorm.Dialector
switch Config.DB {
case "mysql":
conn = mysql.Open(Config.DSN)
case "postgres":
conn = postgres.Open(Config.DSN)
default:
conn = sqlite.Open(Config.DSN)
}
db, err = gorm.Open(conn,
&gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
panic(err)
}
}
return db
}

@ -12,6 +12,7 @@ import (
"github.com/veypi/vbase/cfg" "github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/models" "github.com/veypi/vbase/models"
"github.com/veypi/vigo" "github.com/veypi/vigo"
"github.com/veypi/vigo/contrib/event"
"github.com/veypi/vigo/flags" "github.com/veypi/vigo/flags"
"github.com/veypi/vigo/logv" "github.com/veypi/vigo/logv"
) )
@ -35,7 +36,6 @@ func init() {
cmdMain.Command = runWeb cmdMain.Command = runWeb
cmdDB.SubCommand("migrate", "migrate database").Command = models.Migrate cmdDB.SubCommand("migrate", "migrate database").Command = models.Migrate
cmdDB.SubCommand("drop", "drop database").Command = models.Drop cmdDB.SubCommand("drop", "drop database").Command = models.Drop
cmdDB.SubCommand("init", "init db data").Command = models.InitDB
} }
func main() { func main() {
@ -47,11 +47,8 @@ func main() {
} }
func runWeb() error { func runWeb() error {
// 初始化权限系统 models.Migrate()
if err := vbase.Auth.Init(); err != nil { event.Start()
return err
}
server, err := vigo.New(vigo.WithHost(cliOpts.Host), vigo.WithPort(cliOpts.Port)) server, err := vigo.New(vigo.WithHost(cliOpts.Host), vigo.WithPort(cliOpts.Port))
if err != nil { if err != nil {
return err return err

@ -13,6 +13,7 @@ import (
"github.com/veypi/vbase/cfg" "github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/libs/crypto" "github.com/veypi/vbase/libs/crypto"
"github.com/veypi/vigo" "github.com/veypi/vigo"
"github.com/veypi/vigo/contrib/event"
) )
var AllModels = &vigo.ModelList{} var AllModels = &vigo.ModelList{}
@ -42,6 +43,9 @@ func init() {
AllModels.Add(&VerificationCode{}) AllModels.Add(&VerificationCode{})
AllModels.Add(&EmailLog{}) AllModels.Add(&EmailLog{})
AllModels.Add(&OAuthProvider{}) AllModels.Add(&OAuthProvider{})
event.Add("vb.init.settings", InitSettings)
event.Add("vb.init.oauth", InitOAuthProviders)
event.Add("vb.init.admin", initAdminUser, event.After("vb.init.auth"))
} }
func Migrate() error { func Migrate() error {
@ -52,24 +56,6 @@ func Drop() error {
return AllModels.AutoDrop(cfg.DB()) return AllModels.AutoDrop(cfg.DB())
} }
func InitDB() error {
// 1. 初始化系统配置
if err := InitSettings(); err != nil {
return fmt.Errorf("init settings failed: %w", err)
}
// 2. 初始化 OAuth 提供商
if err := InitOAuthProviders(); err != nil {
return fmt.Errorf("init oauth providers failed: %w", err)
}
// 3. 检查是否需要创建初始管理员
if err := initAdminUser(); err != nil {
return fmt.Errorf("init admin user failed: %w", err)
}
return nil
}
// initAdminUser 如果用户表为空且配置了 init_admin则自动创建管理员 // initAdminUser 如果用户表为空且配置了 init_admin则自动创建管理员
func initAdminUser() error { func initAdminUser() error {
db := cfg.DB() db := cfg.DB()

Loading…
Cancel
Save