feat(redis): 具名化 JS 导出并动态包裹错误(by AI)

This commit is contained in:
AI Engineer 2026-06-21 10:34:06 +08:00
parent f5ba9b2f97
commit 701284368b
4 changed files with 63 additions and 41 deletions

View File

@ -1,5 +1,9 @@
# CHANGELOG - redis # CHANGELOG - redis
## v1.5.6 (2026-06-21)
- **JS 对齐**: 重构 JS 导出为具名函数,并引入 `jsmod.MakeError` 动态包装错误以获取调用栈。
- **依赖更新**: 升级依赖 `jsmod``v1.5.3``cast``v1.5.3``rand``v1.5.3``encoding``v1.5.4``shell``v1.5.3``safe``v1.5.2``id``v1.5.4``crypto``v1.5.3``file``v1.5.5``config``v1.5.3``log``v1.5.8`
## v1.5.5 (2026-06-20) ## v1.5.5 (2026-06-20)
- **JS 导出重构**: - **JS 导出重构**:
- 移除 `js_export.go` 中冗余的独立命令快捷函数SET, GET, DEL, EXISTS, EXPIRE, PUBLISH统一通过 `Do` 方法调用。 - 移除 `js_export.go` 中冗余的独立命令快捷函数SET, GET, DEL, EXISTS, EXPIRE, PUBLISH统一通过 `Do` 方法调用。

View File

@ -16,5 +16,9 @@
- **BenchmarkGetSet**: ~80,000 ns/op (Simple GET/SET loop) - **BenchmarkGetSet**: ~80,000 ns/op (Simple GET/SET loop)
- **BenchmarkIDMaker**: ~2,300 ns/op (High-performance sequence generation) - **BenchmarkIDMaker**: ~2,300 ns/op (High-performance sequence generation)
> Date: 2026-05-05 ## 🛡️ 鲁棒性防御 (Robustness)
- **安全沙箱拦截**:在 `SafeMode` 下,仅允许 GET/EXISTS/ZRANGE 等读操作命令,自动拦截所有写操作命令并返回错误。
- **JS 错误调用栈**JS 桥接层改用具名导出并使用 `jsmod.MakeError` 包裹错误(包括 Do 返回的 Result.Error 字段),确保 JS 抛出异常时携带准确的 Go 运行时堆栈。
> Date: 2026-06-21
> Environment: Darwin / Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz > Environment: Darwin / Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz

22
go.mod
View File

@ -3,21 +3,21 @@ module apigo.cc/go/redis
go 1.25.0 go 1.25.0
require ( require (
apigo.cc/go/cast v1.5.2 apigo.cc/go/cast v1.5.3
apigo.cc/go/config v1.5.2 apigo.cc/go/config v1.5.3
apigo.cc/go/crypto v1.5.2 apigo.cc/go/crypto v1.5.3
apigo.cc/go/encoding v1.5.3 apigo.cc/go/encoding v1.5.4
apigo.cc/go/id v1.5.3 apigo.cc/go/id v1.5.4
apigo.cc/go/jsmod v1.5.2 apigo.cc/go/jsmod v1.5.3
apigo.cc/go/log v1.5.6 apigo.cc/go/log v1.5.8
apigo.cc/go/safe v1.5.1 apigo.cc/go/safe v1.5.2
github.com/gomodule/redigo v2.0.0+incompatible github.com/gomodule/redigo v2.0.0+incompatible
) )
require ( require (
apigo.cc/go/file v1.5.4 // indirect apigo.cc/go/file v1.5.5 // indirect
apigo.cc/go/rand v1.5.2 // indirect apigo.cc/go/rand v1.5.3 // indirect
apigo.cc/go/shell v1.5.2 // indirect apigo.cc/go/shell v1.5.3 // indirect
golang.org/x/crypto v0.52.0 // indirect golang.org/x/crypto v0.52.0 // indirect
golang.org/x/sys v0.45.0 // indirect golang.org/x/sys v0.45.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@ -13,38 +13,46 @@ import (
func init() { func init() {
jsmod.Register("redis", map[string]any{ jsmod.Register("redis", map[string]any{
// 入口:支持别名获取,不传则默认 "default" // 入口:支持别名获取,不传则默认 "default"
"Get": func(ctx context.Context, name *string) (*jsRedis, error) { "Get": jsGet,
target := "default"
if name != nil {
target = *name
}
rd := GetRedis(target, nil)
if rd.Error != nil {
return nil, rd.Error
}
return &jsRedis{rd: rd, ctx: ctx}, nil
},
// 默认快捷调用 (面向 "default" 实例) // 默认快捷调用 (面向 "default" 实例)
"Do": func(ctx context.Context, cmd string, args ...any) (*Result, error) { "Do": jsDo,
jr := getDefaultRedisForJS(ctx) "MakeID": jsMakeID,
if jr.rd.Error != nil {
return nil, jr.rd.Error
}
res := jr.Do(cmd, args...)
return res, res.Error
},
"MakeID": func(ctx context.Context, size int, forDB *string) string {
jr := getDefaultRedisForJS(ctx)
if jr.rd.Error != nil {
return id.MakeID(size)
}
return jr.MakeID(size, forDB)
},
}) })
} }
func jsGet(ctx context.Context, name *string) (*jsRedis, error) {
target := "default"
if name != nil {
target = *name
}
rd := GetRedis(target, nil)
if rd.Error != nil {
return nil, jsmod.MakeError(rd.Error)
}
return &jsRedis{rd: rd, ctx: ctx}, nil
}
func jsDo(ctx context.Context, cmd string, args ...any) (*Result, error) {
jr := getDefaultRedisForJS(ctx)
if jr.rd.Error != nil {
return nil, jsmod.MakeError(jr.rd.Error)
}
res := jr.Do(cmd, args...)
if res != nil && res.Error != nil {
return res, jsmod.MakeError(res.Error)
}
return res, nil
}
func jsMakeID(ctx context.Context, size int, forDB *string) string {
jr := getDefaultRedisForJS(ctx)
if jr.rd.Error != nil {
return id.MakeID(size)
}
return jr.MakeID(size, forDB)
}
type jsRedis struct { type jsRedis struct {
rd *Redis rd *Redis
ctx context.Context ctx context.Context
@ -86,9 +94,15 @@ func (jr *jsRedis) checkSafe(cmd string) error {
func (jr *jsRedis) Do(cmd string, args ...any) *Result { func (jr *jsRedis) Do(cmd string, args ...any) *Result {
if err := jr.checkSafe(cmd); err != nil { if err := jr.checkSafe(cmd); err != nil {
return &Result{Error: err} return &Result{Error: jsmod.MakeError(err)}
} }
return jr.rd.Do(cmd, args...) res := jr.rd.Do(cmd, args...)
if res != nil && res.Error != nil {
resCopy := *res
resCopy.Error = jsmod.MakeError(res.Error)
return &resCopy
}
return res
} }
// ID Generation // ID Generation