Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8336ecc46 | ||
|
|
f2022f25f3 | ||
|
|
d6335d0d41 |
13
CHANGELOG.md
13
CHANGELOG.md
@ -1,5 +1,18 @@
|
|||||||
# CHANGELOG - redis
|
# CHANGELOG - redis
|
||||||
|
|
||||||
|
## v1.5.10 (2026-06-22)
|
||||||
|
- **依赖更新**:
|
||||||
|
- 升级依赖 `id` 至 `v1.5.6`。
|
||||||
|
|
||||||
|
## v1.5.9 (2026-06-21)
|
||||||
|
- **依赖更新**:
|
||||||
|
- 升级依赖 `id` 至 `v1.5.5`(同步修复旧版本 ID 未打乱的 Bug)。
|
||||||
|
|
||||||
|
## v1.5.8 (2026-06-21)
|
||||||
|
- **安全模式优化**: `checkSafe` 从写命令全量拦截改为仅拦截危险命令(`FLUSHDB`/`FLUSHALL`),常规写操作(HSET/HDEL/SET/DEL 等)在安全模式下不再受限。
|
||||||
|
- **Result.Bool() 修复**: 增加 `"OK"` 响应判断(Redis RESP Simple String),解决 SET/SETEX 等命令永远返回 `false` 的问题。
|
||||||
|
- **JS Logger 注入修复**: `getDefaultRedisForJS` 改用 `jsmod.Get(ctx, "Logger")` 替代 `ctx.Value("Logger")`,修复 jsmod Context 下 Logger 始终为 nil 导致的 panic。
|
||||||
|
|
||||||
## v1.5.7 (2026-06-21)
|
## v1.5.7 (2026-06-21)
|
||||||
- **兼容性增强**: 对已废弃的 Redis 命令增加新协议兼容支持。
|
- **兼容性增强**: 对已废弃的 Redis 命令增加新协议兼容支持。
|
||||||
- `SETEX` → `SET key val EX sec`,`SETNX` → `SET key val NX`,`HMSET` → `HSET`,`GETSET` → `SET key val GET`,`ZREVRANGE` → `ZRANGE ... REV`。
|
- `SETEX` → `SET key val EX sec`,`SETNX` → `SET key val NX`,`HMSET` → `HSET`,`GETSET` → `SET key val GET`,`ZREVRANGE` → `ZRANGE ... REV`。
|
||||||
|
|||||||
8
TEST.md
8
TEST.md
@ -13,12 +13,12 @@
|
|||||||
- Fixed `Start()` and `Stop()` logic to prevent redundant goroutines and ensure clean exit.
|
- Fixed `Start()` and `Stop()` logic to prevent redundant goroutines and ensure clean exit.
|
||||||
|
|
||||||
## Benchmarks
|
## Benchmarks
|
||||||
- **BenchmarkGetSet**: ~80,000 ns/op (Simple GET/SET loop)
|
- **BenchmarkGetSet**: **282,638 ns/op** (Simple GET/SET loop)
|
||||||
- **BenchmarkIDMaker**: ~2,300 ns/op (High-performance sequence generation)
|
- **BenchmarkIDMaker**: **2,672 ns/op** (High-performance sequence generation)
|
||||||
|
|
||||||
## 🛡️ 鲁棒性防御 (Robustness)
|
## 🛡️ 鲁棒性防御 (Robustness)
|
||||||
- **安全沙箱拦截**:在 `SafeMode` 下,仅允许 GET/EXISTS/ZRANGE 等读操作命令,自动拦截所有写操作命令并返回错误。
|
- **安全沙箱拦截**:在 `SafeMode` 下,拦截危险命令(FLUSHDB/FLUSHALL),常规写操作(HSET/HDEL/SET/DEL 等)可正常执行。
|
||||||
- **JS 错误调用栈**:JS 桥接层改用具名导出并使用 `jsmod.MakeError` 包裹错误(包括 Do 返回的 Result.Error 字段),确保 JS 抛出异常时携带准确的 Go 运行时堆栈。
|
- **JS 错误调用栈**:JS 桥接层改用具名导出并使用 `jsmod.MakeError` 包裹错误(包括 Do 返回的 Result.Error 字段),确保 JS 抛出异常时携带准确的 Go 运行时堆栈。
|
||||||
|
|
||||||
> Date: 2026-06-21
|
> Date: 2026-06-22
|
||||||
> Environment: Darwin / Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
|
> Environment: Darwin / Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
apigo.cc/go/config v1.5.3
|
apigo.cc/go/config v1.5.3
|
||||||
apigo.cc/go/crypto v1.5.3
|
apigo.cc/go/crypto v1.5.3
|
||||||
apigo.cc/go/encoding v1.5.4
|
apigo.cc/go/encoding v1.5.4
|
||||||
apigo.cc/go/id v1.5.4
|
apigo.cc/go/id v1.5.6
|
||||||
apigo.cc/go/jsmod v1.5.3
|
apigo.cc/go/jsmod v1.5.3
|
||||||
apigo.cc/go/log v1.5.8
|
apigo.cc/go/log v1.5.8
|
||||||
apigo.cc/go/safe v1.5.2
|
apigo.cc/go/safe v1.5.2
|
||||||
|
|||||||
4
go.sum
4
go.sum
@ -8,8 +8,8 @@ apigo.cc/go/encoding v1.5.4 h1:Fk8TrveZATyy8SHukC4ZiqdTSp+QIfsRHtt55xmMK7w=
|
|||||||
apigo.cc/go/encoding v1.5.4/go.mod h1:dShEsZ3gKqBINz7TSOYf4e7/fBCqCY9VzlenoGUQUFM=
|
apigo.cc/go/encoding v1.5.4/go.mod h1:dShEsZ3gKqBINz7TSOYf4e7/fBCqCY9VzlenoGUQUFM=
|
||||||
apigo.cc/go/file v1.5.5 h1:/+HmDumLu6Qk2KuQL63M9lpgzHTDL+QJ8dStOl7e9gs=
|
apigo.cc/go/file v1.5.5 h1:/+HmDumLu6Qk2KuQL63M9lpgzHTDL+QJ8dStOl7e9gs=
|
||||||
apigo.cc/go/file v1.5.5/go.mod h1:xRVNhctvqOKeBemmcRW/BQfgkc3B+vT/UZVdSc7duUo=
|
apigo.cc/go/file v1.5.5/go.mod h1:xRVNhctvqOKeBemmcRW/BQfgkc3B+vT/UZVdSc7duUo=
|
||||||
apigo.cc/go/id v1.5.4 h1:D1Zx9gEZhOgdTgZ4SdmPImhpc9xGiOA33Y+j2MkstzQ=
|
apigo.cc/go/id v1.5.5 h1:fQXfb2WZ4hEtzXkpb9w9o8AOcTZ44fYQfTV6iZ49l8o=
|
||||||
apigo.cc/go/id v1.5.4/go.mod h1:hCTQq+KC1ALWe1FpPERf+W4B6FSulg9FAgOUJDDySiY=
|
apigo.cc/go/id v1.5.5/go.mod h1:hCTQq+KC1ALWe1FpPERf+W4B6FSulg9FAgOUJDDySiY=
|
||||||
apigo.cc/go/jsmod v1.5.3 h1:S3W317bH0QV2NMeRO1E0v6ySIBOfMWYv/NuQJbvqKWU=
|
apigo.cc/go/jsmod v1.5.3 h1:S3W317bH0QV2NMeRO1E0v6ySIBOfMWYv/NuQJbvqKWU=
|
||||||
apigo.cc/go/jsmod v1.5.3/go.mod h1:bmyeZtOAP/j5am+YRnaiM89smysK24K7ebk0koFtsSw=
|
apigo.cc/go/jsmod v1.5.3/go.mod h1:bmyeZtOAP/j5am+YRnaiM89smysK24K7ebk0koFtsSw=
|
||||||
apigo.cc/go/log v1.5.8 h1:/IYtGPWhRjT3OayylDIphkWZIQbpLjqVeSnFEiD3Dy0=
|
apigo.cc/go/log v1.5.8 h1:/IYtGPWhRjT3OayylDIphkWZIQbpLjqVeSnFEiD3Dy0=
|
||||||
|
|||||||
23
js_export.go
23
js_export.go
@ -63,29 +63,26 @@ var defaultRedisForJS *jsRedis
|
|||||||
|
|
||||||
func getDefaultRedisForJS(ctx context.Context) *jsRedis {
|
func getDefaultRedisForJS(ctx context.Context) *jsRedis {
|
||||||
if defaultRedisForJS == nil {
|
if defaultRedisForJS == nil {
|
||||||
defaultRedisForJS = &jsRedis{rd: GetRedis("default", ctx.Value("Logger").(*log.Logger)), ctx: ctx}
|
var logger *log.Logger
|
||||||
|
if l := jsmod.Get(ctx, "Logger"); l != nil {
|
||||||
|
logger = l.(*log.Logger)
|
||||||
|
}
|
||||||
|
defaultRedisForJS = &jsRedis{rd: GetRedis("default", logger), ctx: ctx}
|
||||||
}
|
}
|
||||||
return defaultRedisForJS
|
return defaultRedisForJS
|
||||||
}
|
}
|
||||||
|
|
||||||
var errSafeMode = errors.New("redis operation is restricted in safe mode")
|
var errSafeMode = errors.New("redis operation is restricted in safe mode")
|
||||||
|
|
||||||
// 核心写操作指令集
|
// 危险指令集,安全模式下禁止执行
|
||||||
var writeCommands = map[string]bool{
|
var dangerousCommands = map[string]bool{
|
||||||
"SET": true, "SETEX": true, "SETNX": true, "MSET": true, "MSETNX": true,
|
"FLUSHDB": true,
|
||||||
"DEL": true, "EXPIRE": true, "EXPIREAT": true, "PEXPIRE": true, "PEXPIREAT": true,
|
"FLUSHALL": true,
|
||||||
"HSET": true, "HSETNX": true, "HDEL": true, "HMSET": true,
|
|
||||||
"LPUSH": true, "RPUSH": true, "LPOP": true, "RPOP": true, "LREM": true, "LTRIM": true,
|
|
||||||
"SADD": true, "SREM": true, "SPOP": true, "SMOVE": true,
|
|
||||||
"ZADD": true, "ZREM": true, "ZREMRANGEBYRANK": true, "ZREMRANGEBYSCORE": true,
|
|
||||||
"PUBLISH": true, "FLUSHDB": true, "FLUSHALL": true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jr *jsRedis) checkSafe(cmd string) error {
|
func (jr *jsRedis) checkSafe(cmd string) error {
|
||||||
if jsmod.IsSafeMode(jr.ctx) {
|
if jsmod.IsSafeMode(jr.ctx) {
|
||||||
cmd = strings.ToUpper(cmd)
|
if dangerousCommands[strings.ToUpper(cmd)] {
|
||||||
if writeCommands[cmd] || !strings.Contains(" GET EXISTS ZRANGE HGET HGETALL SMEMBERS SISMEMBER LINDEX LLEN ", " "+cmd+" ") {
|
|
||||||
// 严格模式:不在白名单内的或在黑名单内的都禁止
|
|
||||||
return errSafeMode
|
return errSafeMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"apigo.cc/go/cast"
|
"apigo.cc/go/cast"
|
||||||
)
|
)
|
||||||
@ -58,7 +59,11 @@ func (rs *Result) Bytes() []byte {
|
|||||||
return rs.bytes()
|
return rs.bytes()
|
||||||
}
|
}
|
||||||
func (rs *Result) Bool() bool {
|
func (rs *Result) Bool() bool {
|
||||||
return cast.Bool(rs.String())
|
s := strings.ToLower(rs.String())
|
||||||
|
if s == "ok" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return cast.Bool(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *Result) Ints() []int {
|
func (rs *Result) Ints() []int {
|
||||||
|
|||||||
@ -19,6 +19,7 @@ func TestSub(t *testing.T) {
|
|||||||
rd.Subscribe("aaa", nil, func(s []byte) {
|
rd.Subscribe("aaa", nil, func(s []byte) {
|
||||||
aaa.Store(string(s))
|
aaa.Store(string(s))
|
||||||
})
|
})
|
||||||
|
time.Sleep(50 * time.Millisecond) // 等待 Redis 订阅注册完成
|
||||||
|
|
||||||
rd.PUBLISH("aaa", "111")
|
rd.PUBLISH("aaa", "111")
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
@ -31,6 +32,7 @@ func TestSub(t *testing.T) {
|
|||||||
rd.Subscribe("bbb", nil, func(s []byte) {
|
rd.Subscribe("bbb", nil, func(s []byte) {
|
||||||
bbb.Store(string(s))
|
bbb.Store(string(s))
|
||||||
})
|
})
|
||||||
|
time.Sleep(50 * time.Millisecond) // 等待 Redis 订阅注册完成
|
||||||
|
|
||||||
rd.PUBLISH("bbb", "222")
|
rd.PUBLISH("bbb", "222")
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user