141 lines
3.7 KiB
Go
141 lines
3.7 KiB
Go
package redisx
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"fmt"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/redis/go-redis/v9"
|
||
)
|
||
|
||
// ---------------- 基础方法 ----------------
|
||
|
||
// Set 设置任意 key
|
||
func Set(key string, value interface{}, expire time.Duration) error {
|
||
return Client().Set(context.Background(), key, value, expire).Err()
|
||
}
|
||
|
||
// Get 获取任意 key 的值,返回 string
|
||
func Get(key string) (string, error) {
|
||
val, err := Client().Get(context.Background(), key).Result()
|
||
if errors.Is(err, redis.Nil) {
|
||
return "", nil
|
||
}
|
||
return val, err
|
||
}
|
||
|
||
// Delete 删除任意 key
|
||
func Delete(key string) error {
|
||
return Client().Del(context.Background(), key).Err()
|
||
}
|
||
|
||
// Exists 判断 key 是否存在
|
||
func Exists(key string) (bool, error) {
|
||
cnt, err := Client().Exists(context.Background(), key).Result()
|
||
if err != nil {
|
||
return false, err
|
||
}
|
||
return cnt > 0, nil
|
||
}
|
||
|
||
// SetUserSpaces 初始化用户空间列表(spaceID -> role)
|
||
func SetUserSpaces(ctx context.Context, userID int64, spaces map[int64]int32) error {
|
||
key := fmt.Sprintf("user:%d:spaces", userID)
|
||
|
||
pipe := Client().TxPipeline()
|
||
|
||
// 1. 先清空旧数据
|
||
pipe.Del(ctx, key)
|
||
|
||
// 2. 再写入新数据(如果有)
|
||
if len(spaces) > 0 {
|
||
data := make(map[string]interface{}, len(spaces))
|
||
for spaceID, role := range spaces {
|
||
data[strconv.FormatInt(spaceID, 10)] = role
|
||
}
|
||
pipe.HSet(ctx, key, data)
|
||
}
|
||
|
||
// 3. 执行
|
||
_, err := pipe.Exec(ctx)
|
||
return err
|
||
}
|
||
|
||
// AddOrUpdateUserSpace 添加或更新单个空间的角色(增量更新)
|
||
func AddOrUpdateUserSpace(ctx context.Context, userID, spaceID int64, role int32) error {
|
||
key := fmt.Sprintf("user:%d:spaces", userID)
|
||
return Client().HSet(ctx, key, strconv.FormatInt(spaceID, 10), role).Err()
|
||
}
|
||
|
||
// GetUserSpaces 获取用户所有空间列表和角色
|
||
func GetUserSpaces(ctx context.Context, userID int64) (map[int64]int, error) {
|
||
key := fmt.Sprintf("user:%d:spaces", userID)
|
||
result, err := Client().HGetAll(ctx, key).Result()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
spaces := make(map[int64]int, len(result))
|
||
for k, v := range result {
|
||
spaceID, err1 := strconv.ParseInt(k, 10, 64)
|
||
role, err2 := strconv.Atoi(v)
|
||
if err1 != nil || err2 != nil {
|
||
continue
|
||
}
|
||
spaces[spaceID] = role
|
||
}
|
||
|
||
return spaces, nil
|
||
}
|
||
|
||
// GetUserSpaceRole 获取用户在指定空间的角色
|
||
func GetUserSpaceRole(ctx context.Context, userID int64, spaceID int64) (role int, exists bool, err error) {
|
||
key := fmt.Sprintf("user:%d:spaces", userID)
|
||
val, err := Client().HGet(ctx, key, strconv.FormatInt(spaceID, 10)).Result()
|
||
if err != nil {
|
||
if errors.Is(err, redis.Nil) {
|
||
return 0, false, nil // 用户不在空间
|
||
}
|
||
return 0, false, err
|
||
}
|
||
|
||
role, err = strconv.Atoi(val)
|
||
if err != nil {
|
||
return 0, false, err
|
||
}
|
||
|
||
return role, true, nil
|
||
}
|
||
|
||
// RemoveUserSpace 从用户缓存中删除一个空间(用户退出或被踢)
|
||
func RemoveUserSpace(ctx context.Context, userID int64, spaceID int64) error {
|
||
key := fmt.Sprintf("user:%d:spaces", userID)
|
||
return Client().HDel(ctx, key, strconv.FormatInt(spaceID, 10)).Err()
|
||
}
|
||
|
||
// ClearUserSpaces 删除用户的所有空间列表
|
||
func ClearUserSpaces(ctx context.Context, userID int64) error {
|
||
key := fmt.Sprintf("user:%d:spaces", userID)
|
||
return Client().Del(ctx, key).Err()
|
||
}
|
||
|
||
func InSpace(ctx context.Context, userID, spaceID int64) (bool, error) {
|
||
key := fmt.Sprintf("user:%d:spaces", userID)
|
||
return Client().HExists(ctx, key, strconv.FormatInt(spaceID, 10)).Result()
|
||
}
|
||
|
||
// HasUserSpaces 判断用户是否在 Redis 中有空间缓存
|
||
func HasUserSpaces(ctx context.Context, userID int64) (bool, error) {
|
||
key := fmt.Sprintf("user:%d:spaces", userID)
|
||
|
||
// HLen 返回 hash 的字段数量
|
||
cnt, err := Client().HLen(ctx, key).Result()
|
||
if err != nil {
|
||
return false, err
|
||
}
|
||
|
||
return cnt > 0, nil
|
||
}
|