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 }