Files
2026-02-25 17:31:09 +08:00

175 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
}
/*
Key design:
space:user:{spaceId}:{userId} -> role (string/int)
space:users:{spaceId} -> Set(userId)
*/
// ================== Role ==================
const (
RoleMember int32 = 1
RoleAdmin int32 = 5
RoleOwner int32 = 9
SpaceUserTTL = 10 * time.Minute
)
// ================== Key helpers ==================
func spaceUserKey(spaceId, userId int64) string {
return fmt.Sprintf("space:user:%d:%d", spaceId, userId)
}
func spaceUsersKey(spaceId int64) string {
return fmt.Sprintf("space:users:%d", spaceId)
}
// ================== Domain APIs ==================
// JoinSpace
// - add user to space users set
// - set user role
func JoinSpace(spaceId, userId int64, role int32) error {
ctx := context.Background()
// 1. add to space users
if err := Client().SAdd(ctx, spaceUsersKey(spaceId), userId).Err(); err != nil {
return err
}
// 2. set role
if err := Set(spaceUserKey(spaceId, userId), role, SpaceUserTTL); err != nil {
// rollback
_ = Client().SRem(ctx, spaceUsersKey(spaceId), userId).Err()
return err
}
return nil
}
// LeaveSpace
// - remove user from space
// - delete role cache
func LeaveSpace(spaceId, userId int64) error {
ctx := context.Background()
if err := Client().SRem(ctx, spaceUsersKey(spaceId), userId).Err(); err != nil {
return err
}
return Delete(spaceUserKey(spaceId, userId))
}
// KickSpaceUser = LeaveSpace
func KickSpaceUser(spaceId, userId int64) error {
return LeaveSpace(spaceId, userId)
}
// ChangeSpaceUserRole
func ChangeSpaceUserRole(spaceId, userId int64, role int32) error {
ok, err := IsUserInSpace(spaceId, userId)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("user not in space")
}
return Set(spaceUserKey(spaceId, userId), role, SpaceUserTTL)
}
// ================== Query APIs ==================
// GetSpaceUserRole
// return 0 means not exists
func GetSpaceUserRole(spaceId, userId int64) (int32, error) {
val, err := Get(spaceUserKey(spaceId, userId))
if err != nil || val == "" {
return 0, err
}
r, err := strconv.ParseInt(val, 10, 32)
if err != nil {
return 0, err
}
return int32(r), nil
}
func IsUserInSpace(spaceId, userId int64) (bool, error) {
return Client().
SIsMember(context.Background(), spaceUsersKey(spaceId), userId).
Result()
}
func GetSpaceUsers(spaceId int64) ([]int64, error) {
members, err := Client().
SMembers(context.Background(), spaceUsersKey(spaceId)).
Result()
if err != nil {
return nil, err
}
users := make([]int64, 0, len(members))
for _, m := range members {
uid, err := strconv.ParseInt(m, 10, 64)
if err == nil {
users = append(users, uid)
}
}
return users, nil
}
// CheckRole
// check whether user's role in space >= needRole
func CheckRole(spaceId, userId int64, needRole int32) (bool, error) {
userRole, err := GetSpaceUserRole(spaceId, userId)
if err != nil {
return false, err
}
return userRole == needRole, nil
}