Browse Source
- giftUserResource 入参改为 vipday + compute,后台不再按功能分桶发放分钟数
(那是 2026-09 停用的旧三桶模型);trademin/meetmin 保留为入参兼容,
老 admin 容器与历史脚本送上来的分钟数按当前系数折成算力,进同一个 addcompute。
代理余额只有 balance_vipday/trademin/meetmin 三列、没有算力列,这条路的边界在注释里写明。
- console 读换算系数改用按 X-App-Id 取出的连接(computeRatesOf)。
⚠️ console 是单例服务,InitSys 从不 mysql.OnInit,包级 comm.LoadComputeRates()
一调就 nil interface method call panic,被 gin.Recovery 兜成 HTTP 500,
前端只看得到状态码、拿不到任何业务错误;何况系数本来就按应用存在各自业务库。
新增 pkgdb_boundary_test.go 守这条边界。
- 后台上传 OTA 更新包放开 .upd 扩展名。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
main
5 changed files with 146 additions and 29 deletions
@ -0,0 +1,79 @@ |
|||||
|
package console |
||||
|
|
||||
|
import ( |
||||
|
"go/ast" |
||||
|
"go/parser" |
||||
|
"go/token" |
||||
|
"io/fs" |
||||
|
"strings" |
||||
|
"testing" |
||||
|
) |
||||
|
|
||||
|
// console 是**单例服务**:InitSys 只初始化 postgres(主库)/redis/nats/email,**从不 mysql.OnInit**。
|
||||
|
// 业务库连接是按 X-App-Id 用 mysql.NewSys 现建的实例(registry.buildAppConn),跟包级连接是两回事。
|
||||
|
//
|
||||
|
// 所以包级 mysql 的 defsys 恒为 nil,任何走它的调用都是 nil interface method call panic,
|
||||
|
// 被 gin.Recovery 兜成 HTTP 500 —— 前端只拿得到状态码,看不到任何业务错误信息,极难定位。
|
||||
|
// 2026-09-14 的「赠送资源点」500 就是 giftUserResource 调了 comm.LoadComputeRates() 造成的。
|
||||
|
//
|
||||
|
// 而且这些配置本来就是**按应用**存在各自业务库里的,包级连接即使初始化了也会读到别人那一份。
|
||||
|
// console 侧一律走 conn(见 api_compute.go 的 computeRatesOf / appConnFromCtx)。
|
||||
|
|
||||
|
// comm 包里直接使用包级 mysql/postgres 连接的导出函数,console 不能调。
|
||||
|
var commPkgLevelDBFuncs = map[string]string{ |
||||
|
"LoadOpsParams": "改用 conn.Find(comm.TableAppConfig, ...) + comm.ParseOpsParams", |
||||
|
"LoadComputeRates": "改用 computeRatesOf(conn)", |
||||
|
"SaveComputeRates": "改用 saveComputeConfig 里按 conn 写的那套", |
||||
|
"BoundFactoryDevices": "改用 registry 主库连接自己查 device_mac", |
||||
|
"ResolveUserVip": "改用 userComputeSummary(conn, user) 那条跨库拼装", |
||||
|
"ApplyComputeUsage": "console 不记消耗,只按 conn 调整余额", |
||||
|
"AdjustUserCompute": "改用 api_compute.go 里按 conn 重写的那份", |
||||
|
"GrantUserCompute": "改用 conn.Table(comm.TableUser).Update(...)", |
||||
|
} |
||||
|
|
||||
|
func TestConsoleDoesNotUsePackageLevelDB(t *testing.T) { |
||||
|
fset := token.NewFileSet() |
||||
|
pkgs, err := parser.ParseDir(fset, ".", func(fi fs.FileInfo) bool { |
||||
|
return !strings.HasSuffix(fi.Name(), "_test.go") |
||||
|
}, 0) // 0 = 丢弃注释,注释里提到函数名不算调用
|
||||
|
if err != nil { |
||||
|
t.Fatalf("解析 console 包失败: %v", err) |
||||
|
} |
||||
|
for _, pkg := range pkgs { |
||||
|
for path, f := range pkg.Files { |
||||
|
ast.Inspect(f, func(n ast.Node) bool { |
||||
|
call, ok := n.(*ast.CallExpr) |
||||
|
if !ok { |
||||
|
return true |
||||
|
} |
||||
|
sel, ok := call.Fun.(*ast.SelectorExpr) |
||||
|
if !ok { |
||||
|
return true |
||||
|
} |
||||
|
ident, ok := sel.X.(*ast.Ident) |
||||
|
if !ok { |
||||
|
return true |
||||
|
} |
||||
|
pos := fset.Position(call.Pos()) |
||||
|
switch ident.Name { |
||||
|
case "comm": |
||||
|
if fix, bad := commPkgLevelDBFuncs[sel.Sel.Name]; bad { |
||||
|
t.Errorf("%s:%d: console 不能调 comm.%s —— 它走包级 mysql 连接,"+ |
||||
|
"console 从不初始化,运行时必 panic → HTTP 500。%s", |
||||
|
path, pos.Line, sel.Sel.Name, fix) |
||||
|
} |
||||
|
case "mysql": |
||||
|
// 只允许建实例与设置选项:mysql.NewSys / mysql.SetXxx。
|
||||
|
// 其余(Find/FindOne/Insert/Save/Table/Exec…)都是包级 defsys 的转发。
|
||||
|
name := sel.Sel.Name |
||||
|
if name != "NewSys" && !strings.HasPrefix(name, "Set") { |
||||
|
t.Errorf("%s:%d: console 不能调包级 mysql.%s —— defsys 恒为 nil,"+ |
||||
|
"改用按 X-App-Id 取出的 conn(appConnFromCtx / registry.getServiceDB)", |
||||
|
path, pos.Line, name) |
||||
|
} |
||||
|
} |
||||
|
return true |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue