package main import ( "context" "encoding/base64" "flag" "fmt" "os" "bindbox-game/configs" "bindbox-game/internal/pkg/logger" "bindbox-game/internal/repository/mysql" "bindbox-game/internal/repository/mysql/dao" "bindbox-game/internal/service/sysconfig" ) var ( dryRun = flag.Bool("dry-run", false, "仅打印将要写入的配置,不实际写入数据库") force = flag.Bool("force", false, "强制覆盖已存在的配置") ) func main() { flag.Parse() // 初始化数据库 dbRepo, err := mysql.New() if err != nil { fmt.Printf("数据库连接失败: %v\n", err) os.Exit(1) } // 初始化 logger (简化版) customLogger, err := logger.NewCustomLogger(dao.Use(dbRepo.GetDbW()), logger.WithDebugLevel(), logger.WithOutputInConsole(), ) if err != nil { fmt.Printf("Logger 初始化失败: %v\n", err) os.Exit(1) } ctx := context.Background() // 创建动态配置服务 dynamicCfg := sysconfig.NewDynamicConfig(customLogger, dbRepo) staticCfg := configs.Get() // 定义要迁移的配置项 type configItem struct { Key string Value string Remark string } // 读取证书文件内容并 Base64 编码 readAndEncode := func(path string) string { if path == "" { return "" } data, err := os.ReadFile(path) if err != nil { fmt.Printf("警告: 读取文件 %s 失败: %v\n", path, err) return "" } return base64.StdEncoding.EncodeToString(data) } items := []configItem{ // COS 配置 {sysconfig.KeyCOSBucket, staticCfg.COS.Bucket, "COS Bucket名称"}, {sysconfig.KeyCOSRegion, staticCfg.COS.Region, "COS 地域"}, {sysconfig.KeyCOSSecretID, staticCfg.COS.SecretID, "COS SecretID (加密存储)"}, {sysconfig.KeyCOSSecretKey, staticCfg.COS.SecretKey, "COS SecretKey (加密存储)"}, {sysconfig.KeyCOSBaseURL, staticCfg.COS.BaseURL, "COS 自定义域名"}, // 微信小程序配置 {sysconfig.KeyWechatAppID, staticCfg.Wechat.AppID, "微信小程序 AppID"}, {sysconfig.KeyWechatAppSecret, staticCfg.Wechat.AppSecret, "微信小程序 AppSecret (加密存储)"}, {sysconfig.KeyWechatLotteryResultTemplateID, staticCfg.Wechat.LotteryResultTemplateID, "中奖结果订阅消息模板ID"}, // 微信支付配置 {sysconfig.KeyWechatPayMchID, staticCfg.WechatPay.MchID, "微信支付商户号"}, {sysconfig.KeyWechatPaySerialNo, staticCfg.WechatPay.SerialNo, "微信支付证书序列号"}, {sysconfig.KeyWechatPayPrivateKey, readAndEncode(staticCfg.WechatPay.PrivateKeyPath), "微信支付私钥 (Base64编码, 加密存储)"}, {sysconfig.KeyWechatPayApiV3Key, staticCfg.WechatPay.ApiV3Key, "微信支付 API v3 密钥 (加密存储)"}, {sysconfig.KeyWechatPayNotifyURL, staticCfg.WechatPay.NotifyURL, "微信支付回调地址"}, {sysconfig.KeyWechatPayPublicKeyID, staticCfg.WechatPay.PublicKeyID, "微信支付公钥ID"}, {sysconfig.KeyWechatPayPublicKey, readAndEncode(staticCfg.WechatPay.PublicKeyPath), "微信支付公钥 (Base64编码, 加密存储)"}, // 阿里云短信配置 {sysconfig.KeyAliyunSMSAccessKeyID, staticCfg.AliyunSMS.AccessKeyID, "阿里云短信 AccessKeyID"}, {sysconfig.KeyAliyunSMSAccessKeySecret, staticCfg.AliyunSMS.AccessKeySecret, "阿里云短信 AccessKeySecret (加密存储)"}, {sysconfig.KeyAliyunSMSSignName, staticCfg.AliyunSMS.SignName, "短信签名"}, {sysconfig.KeyAliyunSMSTemplateCode, staticCfg.AliyunSMS.TemplateCode, "短信模板Code"}, } fmt.Println("========== 配置迁移工具 ==========") fmt.Printf("环境: %s\n", configs.ProjectName) fmt.Printf("Dry Run: %v\n", *dryRun) fmt.Printf("Force: %v\n", *force) fmt.Println() successCount := 0 skipCount := 0 failCount := 0 for _, item := range items { if item.Value == "" { fmt.Printf("[跳过] %s: 值为空\n", item.Key) skipCount++ continue } // 检查是否已存在 existing := dynamicCfg.Get(ctx, item.Key) if existing != "" && !*force { fmt.Printf("[跳过] %s: 已存在 (使用 -force 覆盖)\n", item.Key) skipCount++ continue } // 脱敏显示 displayValue := item.Value if sysconfig.IsSensitiveKey(item.Key) { if len(displayValue) > 8 { displayValue = displayValue[:4] + "****" + displayValue[len(displayValue)-4:] } else { displayValue = "****" } } else if len(displayValue) > 50 { displayValue = displayValue[:50] + "..." } if *dryRun { fmt.Printf("[预览] %s = %s\n", item.Key, displayValue) successCount++ } else { if err := dynamicCfg.Set(ctx, item.Key, item.Value, item.Remark); err != nil { fmt.Printf("[失败] %s: %v\n", item.Key, err) failCount++ } else { fmt.Printf("[成功] %s = %s\n", item.Key, displayValue) successCount++ } } } fmt.Println() fmt.Printf("========== 迁移结果 ==========\n") fmt.Printf("成功: %d, 跳过: %d, 失败: %d\n", successCount, skipCount, failCount) if *dryRun { fmt.Println("\n这只是预览,使用不带 -dry-run 参数执行实际迁移") } }