Spaces:
Build error
Build error
| package model | |
| import ( | |
| "fmt" | |
| "one-api/common" | |
| "one-api/constant" | |
| "one-api/dto" | |
| "time" | |
| "github.com/gin-gonic/gin" | |
| "github.com/bytedance/gopkg/util/gopool" | |
| ) | |
| // UserBase struct remains the same as it represents the cached data structure | |
| type UserBase struct { | |
| Id int `json:"id"` | |
| Group string `json:"group"` | |
| Email string `json:"email"` | |
| Quota int `json:"quota"` | |
| Status int `json:"status"` | |
| Username string `json:"username"` | |
| Setting string `json:"setting"` | |
| } | |
| func (user *UserBase) WriteContext(c *gin.Context) { | |
| common.SetContextKey(c, constant.ContextKeyUserGroup, user.Group) | |
| common.SetContextKey(c, constant.ContextKeyUserQuota, user.Quota) | |
| common.SetContextKey(c, constant.ContextKeyUserStatus, user.Status) | |
| common.SetContextKey(c, constant.ContextKeyUserEmail, user.Email) | |
| common.SetContextKey(c, constant.ContextKeyUserName, user.Username) | |
| common.SetContextKey(c, constant.ContextKeyUserSetting, user.GetSetting()) | |
| } | |
| func (user *UserBase) GetSetting() dto.UserSetting { | |
| setting := dto.UserSetting{} | |
| if user.Setting != "" { | |
| err := common.Unmarshal([]byte(user.Setting), &setting) | |
| if err != nil { | |
| common.SysLog("failed to unmarshal setting: " + err.Error()) | |
| } | |
| } | |
| return setting | |
| } | |
| // getUserCacheKey returns the key for user cache | |
| func getUserCacheKey(userId int) string { | |
| return fmt.Sprintf("user:%d", userId) | |
| } | |
| // invalidateUserCache clears user cache | |
| func invalidateUserCache(userId int) error { | |
| if !common.RedisEnabled { | |
| return nil | |
| } | |
| return common.RedisDelKey(getUserCacheKey(userId)) | |
| } | |
| // updateUserCache updates all user cache fields using hash | |
| func updateUserCache(user User) error { | |
| if !common.RedisEnabled { | |
| return nil | |
| } | |
| return common.RedisHSetObj( | |
| getUserCacheKey(user.Id), | |
| user.ToBaseUser(), | |
| time.Duration(common.RedisKeyCacheSeconds())*time.Second, | |
| ) | |
| } | |
| // GetUserCache gets complete user cache from hash | |
| func GetUserCache(userId int) (userCache *UserBase, err error) { | |
| var user *User | |
| var fromDB bool | |
| defer func() { | |
| // Update Redis cache asynchronously on successful DB read | |
| if shouldUpdateRedis(fromDB, err) && user != nil { | |
| gopool.Go(func() { | |
| if err := updateUserCache(*user); err != nil { | |
| common.SysLog("failed to update user status cache: " + err.Error()) | |
| } | |
| }) | |
| } | |
| }() | |
| // Try getting from Redis first | |
| userCache, err = cacheGetUserBase(userId) | |
| if err == nil { | |
| return userCache, nil | |
| } | |
| // If Redis fails, get from DB | |
| fromDB = true | |
| user, err = GetUserById(userId, false) | |
| if err != nil { | |
| return nil, err // Return nil and error if DB lookup fails | |
| } | |
| // Create cache object from user data | |
| userCache = &UserBase{ | |
| Id: user.Id, | |
| Group: user.Group, | |
| Quota: user.Quota, | |
| Status: user.Status, | |
| Username: user.Username, | |
| Setting: user.Setting, | |
| Email: user.Email, | |
| } | |
| return userCache, nil | |
| } | |
| func cacheGetUserBase(userId int) (*UserBase, error) { | |
| if !common.RedisEnabled { | |
| return nil, fmt.Errorf("redis is not enabled") | |
| } | |
| var userCache UserBase | |
| // Try getting from Redis first | |
| err := common.RedisHGetObj(getUserCacheKey(userId), &userCache) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return &userCache, nil | |
| } | |
| // Add atomic quota operations using hash fields | |
| func cacheIncrUserQuota(userId int, delta int64) error { | |
| if !common.RedisEnabled { | |
| return nil | |
| } | |
| return common.RedisHIncrBy(getUserCacheKey(userId), "Quota", delta) | |
| } | |
| func cacheDecrUserQuota(userId int, delta int64) error { | |
| return cacheIncrUserQuota(userId, -delta) | |
| } | |
| // Helper functions to get individual fields if needed | |
| func getUserGroupCache(userId int) (string, error) { | |
| cache, err := GetUserCache(userId) | |
| if err != nil { | |
| return "", err | |
| } | |
| return cache.Group, nil | |
| } | |
| func getUserQuotaCache(userId int) (int, error) { | |
| cache, err := GetUserCache(userId) | |
| if err != nil { | |
| return 0, err | |
| } | |
| return cache.Quota, nil | |
| } | |
| func getUserStatusCache(userId int) (int, error) { | |
| cache, err := GetUserCache(userId) | |
| if err != nil { | |
| return 0, err | |
| } | |
| return cache.Status, nil | |
| } | |
| func getUserNameCache(userId int) (string, error) { | |
| cache, err := GetUserCache(userId) | |
| if err != nil { | |
| return "", err | |
| } | |
| return cache.Username, nil | |
| } | |
| func getUserSettingCache(userId int) (dto.UserSetting, error) { | |
| cache, err := GetUserCache(userId) | |
| if err != nil { | |
| return dto.UserSetting{}, err | |
| } | |
| return cache.GetSetting(), nil | |
| } | |
| // New functions for individual field updates | |
| func updateUserStatusCache(userId int, status bool) error { | |
| if !common.RedisEnabled { | |
| return nil | |
| } | |
| statusInt := common.UserStatusEnabled | |
| if !status { | |
| statusInt = common.UserStatusDisabled | |
| } | |
| return common.RedisHSetField(getUserCacheKey(userId), "Status", fmt.Sprintf("%d", statusInt)) | |
| } | |
| func updateUserQuotaCache(userId int, quota int) error { | |
| if !common.RedisEnabled { | |
| return nil | |
| } | |
| return common.RedisHSetField(getUserCacheKey(userId), "Quota", fmt.Sprintf("%d", quota)) | |
| } | |
| func updateUserGroupCache(userId int, group string) error { | |
| if !common.RedisEnabled { | |
| return nil | |
| } | |
| return common.RedisHSetField(getUserCacheKey(userId), "Group", group) | |
| } | |
| func updateUserNameCache(userId int, username string) error { | |
| if !common.RedisEnabled { | |
| return nil | |
| } | |
| return common.RedisHSetField(getUserCacheKey(userId), "Username", username) | |
| } | |
| func updateUserSettingCache(userId int, setting string) error { | |
| if !common.RedisEnabled { | |
| return nil | |
| } | |
| return common.RedisHSetField(getUserCacheKey(userId), "Setting", setting) | |
| } | |