mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-05-11 17:49:46 +08:00
- Redis 页面重构为工作台样式,统一左右面板、工具条和详情区层级 - 接入 light/dark/透明模式主题参数,修复 Redis 页面与全局主题不一致问题 - 新增文件夹递归勾选、全选全部、分组全选/取消全选能力 - 支持 Redis Key 右键菜单重命名并同步更新树节点、选中态和详情面板 - 修复 type=none 时读取失败问题,过期或已删除 Key 自动提示并移出列表 - 接管 Redis Tree 展开箭头渲染,修复 switcher 命中区错位和悬浮白线问题 - 统一工具、代理、主题、关于、筛选、新建组和新建连接等弹层主题 - refs #231
648 lines
20 KiB
Go
648 lines
20 KiB
Go
package app
|
||
|
||
import (
|
||
"crypto/sha256"
|
||
"encoding/hex"
|
||
"encoding/json"
|
||
"fmt"
|
||
"math"
|
||
"strconv"
|
||
"strings"
|
||
"sync"
|
||
|
||
"GoNavi-Wails/internal/connection"
|
||
"GoNavi-Wails/internal/logger"
|
||
"GoNavi-Wails/internal/redis"
|
||
)
|
||
|
||
// Redis client cache
|
||
var (
|
||
redisCache = make(map[string]redis.RedisClient)
|
||
redisCacheMu sync.Mutex
|
||
)
|
||
|
||
// getRedisClient gets or creates a Redis client from cache
|
||
func (a *App) getRedisClient(config connection.ConnectionConfig) (redis.RedisClient, error) {
|
||
effectiveConfig := applyGlobalProxyToConnection(config)
|
||
connectConfig, proxyErr := resolveDialConfigWithProxy(effectiveConfig)
|
||
if proxyErr != nil {
|
||
wrapped := wrapConnectError(effectiveConfig, proxyErr)
|
||
logger.Error(wrapped, "Redis 代理准备失败:%s", formatRedisConnSummary(effectiveConfig))
|
||
return nil, wrapped
|
||
}
|
||
|
||
key := getRedisClientCacheKey(connectConfig)
|
||
shortKey := key
|
||
if len(shortKey) > 12 {
|
||
shortKey = shortKey[:12]
|
||
}
|
||
logger.Infof("获取 Redis 连接:%s 缓存Key=%s", formatRedisConnSummary(effectiveConfig), shortKey)
|
||
|
||
redisCacheMu.Lock()
|
||
defer redisCacheMu.Unlock()
|
||
|
||
if client, ok := redisCache[key]; ok {
|
||
logger.Infof("命中 Redis 连接缓存,开始检测可用性:缓存Key=%s", shortKey)
|
||
if err := client.Ping(); err == nil {
|
||
logger.Infof("缓存 Redis 连接可用:缓存Key=%s", shortKey)
|
||
return client, nil
|
||
} else {
|
||
logger.Error(err, "缓存 Redis 连接不可用,准备重建:缓存Key=%s", shortKey)
|
||
}
|
||
client.Close()
|
||
delete(redisCache, key)
|
||
}
|
||
|
||
logger.Infof("创建 Redis 客户端实例:缓存Key=%s", shortKey)
|
||
client := redis.NewRedisClient()
|
||
if err := client.Connect(connectConfig); err != nil {
|
||
wrapped := wrapConnectError(effectiveConfig, err)
|
||
logger.Error(wrapped, "Redis 连接失败:%s 缓存Key=%s", formatRedisConnSummary(effectiveConfig), shortKey)
|
||
return nil, wrapped
|
||
}
|
||
|
||
redisCache[key] = client
|
||
logger.Infof("Redis 连接成功并写入缓存:%s 缓存Key=%s", formatRedisConnSummary(effectiveConfig), shortKey)
|
||
return client, nil
|
||
}
|
||
|
||
func getRedisClientCacheKey(config connection.ConnectionConfig) string {
|
||
normalized := normalizeCacheKeyConfig(config)
|
||
b, _ := json.Marshal(normalized)
|
||
sum := sha256.Sum256(b)
|
||
return hex.EncodeToString(sum[:])
|
||
}
|
||
|
||
func formatRedisConnSummary(config connection.ConnectionConfig) string {
|
||
var b strings.Builder
|
||
b.WriteString("类型=redis 地址=")
|
||
b.WriteString(config.Host)
|
||
b.WriteString(":")
|
||
b.WriteString(strconv.Itoa(config.Port))
|
||
if topology := strings.TrimSpace(config.Topology); topology != "" {
|
||
b.WriteString(" 模式=")
|
||
b.WriteString(topology)
|
||
}
|
||
if len(config.Hosts) > 0 {
|
||
b.WriteString(" 节点数=")
|
||
b.WriteString(strconv.Itoa(len(config.Hosts)))
|
||
}
|
||
b.WriteString(" DB=")
|
||
b.WriteString(strconv.Itoa(config.RedisDB))
|
||
|
||
if config.UseSSH {
|
||
b.WriteString(" SSH=")
|
||
b.WriteString(config.SSH.Host)
|
||
b.WriteString(":")
|
||
b.WriteString(strconv.Itoa(config.SSH.Port))
|
||
b.WriteString(" 用户=")
|
||
b.WriteString(config.SSH.User)
|
||
}
|
||
if config.UseProxy {
|
||
b.WriteString(" 代理=")
|
||
b.WriteString(strings.ToLower(strings.TrimSpace(config.Proxy.Type)))
|
||
b.WriteString("://")
|
||
b.WriteString(config.Proxy.Host)
|
||
b.WriteString(":")
|
||
b.WriteString(strconv.Itoa(config.Proxy.Port))
|
||
if strings.TrimSpace(config.Proxy.User) != "" {
|
||
b.WriteString(" 代理认证=已配置")
|
||
}
|
||
}
|
||
if config.UseHTTPTunnel {
|
||
b.WriteString(" HTTP隧道=")
|
||
b.WriteString(strings.TrimSpace(config.HTTPTunnel.Host))
|
||
b.WriteString(":")
|
||
b.WriteString(strconv.Itoa(config.HTTPTunnel.Port))
|
||
if strings.TrimSpace(config.HTTPTunnel.User) != "" {
|
||
b.WriteString(" HTTP隧道认证=已配置")
|
||
}
|
||
}
|
||
|
||
return b.String()
|
||
}
|
||
|
||
// RedisConnect tests a Redis connection
|
||
func (a *App) RedisConnect(config connection.ConnectionConfig) connection.QueryResult {
|
||
config.Type = "redis"
|
||
_, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
logger.Error(err, "RedisConnect 连接失败:%s", formatRedisConnSummary(config))
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
logger.Infof("RedisConnect 连接成功:%s", formatRedisConnSummary(config))
|
||
return connection.QueryResult{Success: true, Message: "连接成功"}
|
||
}
|
||
|
||
// RedisTestConnection tests a Redis connection (alias for RedisConnect)
|
||
func (a *App) RedisTestConnection(config connection.ConnectionConfig) connection.QueryResult {
|
||
return a.RedisConnect(config)
|
||
}
|
||
|
||
// RedisScanKeys scans keys matching a pattern
|
||
func (a *App) RedisScanKeys(config connection.ConnectionConfig, pattern string, cursor any, count int64) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
parsedCursor, err := parseRedisScanCursor(cursor)
|
||
if err != nil {
|
||
logger.Warnf("RedisScanKeys 游标解析失败,已回退到起始游标:cursor=%v err=%v", cursor, err)
|
||
parsedCursor = 0
|
||
}
|
||
|
||
result, err := client.ScanKeys(pattern, parsedCursor, count)
|
||
if err != nil {
|
||
logger.Error(err, "RedisScanKeys 扫描失败:pattern=%s", pattern)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Data: result}
|
||
}
|
||
|
||
func parseRedisScanCursor(cursor any) (uint64, error) {
|
||
switch v := cursor.(type) {
|
||
case nil:
|
||
return 0, nil
|
||
case uint64:
|
||
return v, nil
|
||
case uint32:
|
||
return uint64(v), nil
|
||
case uint16:
|
||
return uint64(v), nil
|
||
case uint8:
|
||
return uint64(v), nil
|
||
case uint:
|
||
return uint64(v), nil
|
||
case int64:
|
||
if v < 0 {
|
||
return 0, fmt.Errorf("游标不能为负数: %d", v)
|
||
}
|
||
return uint64(v), nil
|
||
case int32:
|
||
if v < 0 {
|
||
return 0, fmt.Errorf("游标不能为负数: %d", v)
|
||
}
|
||
return uint64(v), nil
|
||
case int16:
|
||
if v < 0 {
|
||
return 0, fmt.Errorf("游标不能为负数: %d", v)
|
||
}
|
||
return uint64(v), nil
|
||
case int8:
|
||
if v < 0 {
|
||
return 0, fmt.Errorf("游标不能为负数: %d", v)
|
||
}
|
||
return uint64(v), nil
|
||
case int:
|
||
if v < 0 {
|
||
return 0, fmt.Errorf("游标不能为负数: %d", v)
|
||
}
|
||
return uint64(v), nil
|
||
case float64:
|
||
return parseRedisScanCursorFromFloat(v)
|
||
case float32:
|
||
return parseRedisScanCursorFromFloat(float64(v))
|
||
case json.Number:
|
||
return parseRedisScanCursor(strings.TrimSpace(v.String()))
|
||
case string:
|
||
trimmed := strings.TrimSpace(v)
|
||
if trimmed == "" {
|
||
return 0, nil
|
||
}
|
||
parsed, err := strconv.ParseUint(trimmed, 10, 64)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("无效游标: %q", v)
|
||
}
|
||
return parsed, nil
|
||
default:
|
||
return 0, fmt.Errorf("不支持的游标类型: %T", cursor)
|
||
}
|
||
}
|
||
|
||
func parseRedisScanCursorFromFloat(value float64) (uint64, error) {
|
||
if math.IsNaN(value) || math.IsInf(value, 0) {
|
||
return 0, fmt.Errorf("无效浮点游标: %v", value)
|
||
}
|
||
if value < 0 {
|
||
return 0, fmt.Errorf("游标不能为负数: %v", value)
|
||
}
|
||
if math.Trunc(value) != value {
|
||
return 0, fmt.Errorf("游标必须为整数: %v", value)
|
||
}
|
||
if value > float64(math.MaxUint64) {
|
||
return 0, fmt.Errorf("游标超出范围: %v", value)
|
||
}
|
||
return uint64(value), nil
|
||
}
|
||
|
||
// RedisGetValue gets the value of a key
|
||
func (a *App) RedisGetValue(config connection.ConnectionConfig, key string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
value, err := client.GetValue(key)
|
||
if err != nil {
|
||
logger.Error(err, "RedisGetValue 获取失败:key=%s", key)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Data: value}
|
||
}
|
||
|
||
// RedisSetString sets a string value
|
||
func (a *App) RedisSetString(config connection.ConnectionConfig, key, value string, ttl int64) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.SetString(key, value, ttl); err != nil {
|
||
logger.Error(err, "RedisSetString 设置失败:key=%s", key)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "设置成功"}
|
||
}
|
||
|
||
// RedisSetHashField sets a field in a hash
|
||
func (a *App) RedisSetHashField(config connection.ConnectionConfig, key, field, value string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.SetHashField(key, field, value); err != nil {
|
||
logger.Error(err, "RedisSetHashField 设置失败:key=%s field=%s", key, field)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "设置成功"}
|
||
}
|
||
|
||
// RedisDeleteKeys deletes one or more keys
|
||
func (a *App) RedisDeleteKeys(config connection.ConnectionConfig, keys []string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
deleted, err := client.DeleteKeys(keys)
|
||
if err != nil {
|
||
logger.Error(err, "RedisDeleteKeys 删除失败:keys=%v", keys)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Data: map[string]int64{"deleted": deleted}}
|
||
}
|
||
|
||
// RedisSetTTL sets the TTL of a key
|
||
func (a *App) RedisSetTTL(config connection.ConnectionConfig, key string, ttl int64) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.SetTTL(key, ttl); err != nil {
|
||
logger.Error(err, "RedisSetTTL 设置失败:key=%s ttl=%d", key, ttl)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "设置成功"}
|
||
}
|
||
|
||
// RedisExecuteCommand executes a raw Redis command
|
||
func (a *App) RedisExecuteCommand(config connection.ConnectionConfig, command string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
// Parse command string into args
|
||
args := parseRedisCommand(command)
|
||
if len(args) == 0 {
|
||
return connection.QueryResult{Success: false, Message: "命令不能为空"}
|
||
}
|
||
|
||
result, err := client.ExecuteCommand(args)
|
||
if err != nil {
|
||
logger.Error(err, "RedisExecuteCommand 执行失败:command=%s", command)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Data: result}
|
||
}
|
||
|
||
// parseRedisCommand parses a Redis command string into arguments
|
||
func parseRedisCommand(command string) []string {
|
||
command = strings.TrimSpace(command)
|
||
if command == "" {
|
||
return nil
|
||
}
|
||
|
||
var args []string
|
||
var current strings.Builder
|
||
inQuote := false
|
||
quoteChar := rune(0)
|
||
|
||
for _, ch := range command {
|
||
if inQuote {
|
||
if ch == quoteChar {
|
||
inQuote = false
|
||
args = append(args, current.String())
|
||
current.Reset()
|
||
} else {
|
||
current.WriteRune(ch)
|
||
}
|
||
} else {
|
||
if ch == '"' || ch == '\'' {
|
||
inQuote = true
|
||
quoteChar = ch
|
||
} else if ch == ' ' || ch == '\t' {
|
||
if current.Len() > 0 {
|
||
args = append(args, current.String())
|
||
current.Reset()
|
||
}
|
||
} else {
|
||
current.WriteRune(ch)
|
||
}
|
||
}
|
||
}
|
||
|
||
if current.Len() > 0 {
|
||
args = append(args, current.String())
|
||
}
|
||
|
||
return args
|
||
}
|
||
|
||
// RedisGetServerInfo returns server information
|
||
func (a *App) RedisGetServerInfo(config connection.ConnectionConfig) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
info, err := client.GetServerInfo()
|
||
if err != nil {
|
||
logger.Error(err, "RedisGetServerInfo 获取失败")
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Data: info}
|
||
}
|
||
|
||
// RedisGetDatabases returns information about all databases
|
||
func (a *App) RedisGetDatabases(config connection.ConnectionConfig) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
dbs, err := client.GetDatabases()
|
||
if err != nil {
|
||
logger.Error(err, "RedisGetDatabases 获取失败")
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Data: dbs}
|
||
}
|
||
|
||
// RedisSelectDB selects a database
|
||
func (a *App) RedisSelectDB(config connection.ConnectionConfig, dbIndex int) connection.QueryResult {
|
||
config.Type = "redis"
|
||
config.RedisDB = dbIndex
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.SelectDB(dbIndex); err != nil {
|
||
logger.Error(err, "RedisSelectDB 切换失败:db=%d", dbIndex)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "切换成功"}
|
||
}
|
||
|
||
// RedisRenameKey renames a key
|
||
func (a *App) RedisRenameKey(config connection.ConnectionConfig, oldKey, newKey string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.RenameKey(oldKey, newKey); err != nil {
|
||
logger.Error(err, "RedisRenameKey 重命名失败:%s -> %s", oldKey, newKey)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "重命名成功"}
|
||
}
|
||
|
||
// RedisKeyExists checks whether a key already exists
|
||
func (a *App) RedisKeyExists(config connection.ConnectionConfig, key string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
exists, err := client.KeyExists(key)
|
||
if err != nil {
|
||
logger.Error(err, "RedisKeyExists 检查失败:key=%s", key)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Data: map[string]bool{"exists": exists}}
|
||
}
|
||
|
||
// RedisDeleteHashField deletes fields from a hash
|
||
func (a *App) RedisDeleteHashField(config connection.ConnectionConfig, key string, fields []string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.DeleteHashField(key, fields...); err != nil {
|
||
logger.Error(err, "RedisDeleteHashField 删除失败:key=%s fields=%v", key, fields)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "删除成功"}
|
||
}
|
||
|
||
// RedisListPush pushes values to a list
|
||
func (a *App) RedisListPush(config connection.ConnectionConfig, key string, values []string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.ListPush(key, values...); err != nil {
|
||
logger.Error(err, "RedisListPush 添加失败:key=%s", key)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "添加成功"}
|
||
}
|
||
|
||
// RedisListSet sets a value at an index in a list
|
||
func (a *App) RedisListSet(config connection.ConnectionConfig, key string, index int64, value string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.ListSet(key, index, value); err != nil {
|
||
logger.Error(err, "RedisListSet 设置失败:key=%s index=%d", key, index)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "设置成功"}
|
||
}
|
||
|
||
// RedisSetAdd adds members to a set
|
||
func (a *App) RedisSetAdd(config connection.ConnectionConfig, key string, members []string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.SetAdd(key, members...); err != nil {
|
||
logger.Error(err, "RedisSetAdd 添加失败:key=%s", key)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "添加成功"}
|
||
}
|
||
|
||
// RedisSetRemove removes members from a set
|
||
func (a *App) RedisSetRemove(config connection.ConnectionConfig, key string, members []string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.SetRemove(key, members...); err != nil {
|
||
logger.Error(err, "RedisSetRemove 删除失败:key=%s", key)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "删除成功"}
|
||
}
|
||
|
||
// RedisZSetAdd adds members to a sorted set
|
||
func (a *App) RedisZSetAdd(config connection.ConnectionConfig, key string, members []redis.ZSetMember) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.ZSetAdd(key, members...); err != nil {
|
||
logger.Error(err, "RedisZSetAdd 添加失败:key=%s", key)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "添加成功"}
|
||
}
|
||
|
||
// RedisZSetRemove removes members from a sorted set
|
||
func (a *App) RedisZSetRemove(config connection.ConnectionConfig, key string, members []string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.ZSetRemove(key, members...); err != nil {
|
||
logger.Error(err, "RedisZSetRemove 删除失败:key=%s", key)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "删除成功"}
|
||
}
|
||
|
||
// RedisStreamAdd adds an entry to a stream
|
||
func (a *App) RedisStreamAdd(config connection.ConnectionConfig, key string, fields map[string]string, id string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
newID, err := client.StreamAdd(key, fields, id)
|
||
if err != nil {
|
||
logger.Error(err, "RedisStreamAdd 添加失败:key=%s id=%s", key, id)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "添加成功", Data: map[string]string{"id": newID}}
|
||
}
|
||
|
||
// RedisStreamDelete deletes stream entries by IDs
|
||
func (a *App) RedisStreamDelete(config connection.ConnectionConfig, key string, ids []string) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
deleted, err := client.StreamDelete(key, ids...)
|
||
if err != nil {
|
||
logger.Error(err, "RedisStreamDelete 删除失败:key=%s ids=%v", key, ids)
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "删除成功", Data: map[string]int64{"deleted": deleted}}
|
||
}
|
||
|
||
// RedisFlushDB flushes the current database
|
||
func (a *App) RedisFlushDB(config connection.ConnectionConfig) connection.QueryResult {
|
||
config.Type = "redis"
|
||
client, err := a.getRedisClient(config)
|
||
if err != nil {
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
if err := client.FlushDB(); err != nil {
|
||
logger.Error(err, "RedisFlushDB 清空失败")
|
||
return connection.QueryResult{Success: false, Message: err.Error()}
|
||
}
|
||
|
||
return connection.QueryResult{Success: true, Message: "清空成功"}
|
||
}
|
||
|
||
// CloseAllRedisClients closes all cached Redis clients (called on shutdown)
|
||
func CloseAllRedisClients() {
|
||
redisCacheMu.Lock()
|
||
defer redisCacheMu.Unlock()
|
||
|
||
for key, client := range redisCache {
|
||
if client != nil {
|
||
client.Close()
|
||
logger.Infof("已关闭 Redis 连接:%s", key[:12])
|
||
}
|
||
}
|
||
redisCache = make(map[string]redis.RedisClient)
|
||
}
|