package room_c import ( "context" "errors" "fmt" "git.hilo.cn/hilo-common/mylogrus" "git.hilo.cn/hilo-common/resource/config" "git.hilo.cn/hilo-common/resource/redisCli" "github.com/bluele/gcache" redis2 "github.com/go-redis/redis/v8" "github.com/spf13/cast" "hilo-group/_const/redis_key" "strconv" "time" ) // 处理访问房间的相关缓存 func ProcessRoomVisit(groupId string, userId uint64) error { key := redis_key.GetPrefixGroupInUserDuration(groupId) now := time.Now() ret, err := redisCli.GetRedis().ZAdd(context.Background(), key, &redis2.Z{ Score: float64(now.Unix()), Member: userId, }).Result() if err != nil { return err } mylogrus.MyLog.Infof("ProcessRoomVisit, ZADD %s, return %d", key, ret) // 每群定时清一次数据可以了 if now.Second()%redis_key.GroupInDurationClearPeriod == 0 { rc, err := clearRoomVisit(groupId, now.AddDate(0, 0, -redis_key.GroupInDurationTTL)) if err == nil { mylogrus.MyLog.Infof("ProcessRoomVisit, clearRoomVisit %s, return %d", key, rc) } else { mylogrus.MyLog.Warnf("ProcessRoomVisit, clearRoomVisit %s, failed %s", key, err.Error()) } } // 马上更新roomVisitCount if _, err := GetSetRoomVisitCount(groupId); err != nil { mylogrus.MyLog.Warnf("ProcessRoomVisit, failed for key %s, err: %s", key, err.Error()) } return nil } func ProcessUserRoomVisit(userId uint64, groupId string) error { key := redis_key.GetUserEnterRoomKey(userId) now := time.Now() ret, err := redisCli.GetRedis().ZAdd(context.Background(), key, &redis2.Z{ Score: float64(now.Unix()), Member: groupId, }).Result() if err != nil { return err } mylogrus.MyLog.Infof("ProcessUserRoomVisit, ZADD %s, return %d", key, ret) return nil } // 查询用户访问过的房间及其时间 // todo 去掉查询,redis性能 func GetUserRoomVisit(userId uint64) (map[string]int64, error) { result := make(map[string]int64, 0) return result, nil key := redis_key.GetUserEnterRoomKey(userId) ret, err := redisCli.GetRedis().ZRangeWithScores(context.Background(), key, 0, -1).Result() if err != nil { return nil, err } //mylogrus.MyLog.Infof("GetUserRoomVisit, ZRangeWithScores %s, return %v", key, ret) for _, i := range ret { result[i.Member.(string)] = int64(i.Score) } return result, nil } var roomVisitCntCache = gcache.New(50000).LRU().Build() // 批量获取房间访问人数 // 带上lru func MGetRoomVisitCount(groupIds []string) (map[string]string, error) { visit := make(map[string]string) if len(groupIds) <= 0 { return visit, nil } // 用redisCluster中的zset代替,只是取出大于100的 zKey := redis_key.GetPrefixRoomVisitCountZset() cnt := 100 if !config.AppIsRelease() { cnt = 0 } zRes, err := redisCli.GetClusterRedis().ZRevRangeByScoreWithScores(context.Background(), zKey, &redis2.ZRangeBy{ Min: fmt.Sprintf("%d", cnt), // 100人数以上的。 Max: "+inf", }).Result() if err != nil { mylogrus.MyLog.Errorf("MGetRoomVisitCount zset fail:%v", err) return visit, err } for _, v := range zRes { visit[cast.ToString(v.Member)] = cast.ToString(v.Score) } return visit, nil var miss []string for _, groupId := range groupIds { if data, err := roomVisitCntCache.Get(groupId); err == nil { visit[groupId] = data.(string) } else { miss = append(miss, groupId) } } if len(miss) <= 0 { return visit, nil } key := redis_key.GetPrefixRoomVisitCount() res, err := redisCli.GetRedis().HMGet(context.Background(), key, miss...).Result() // todo 后续用zset key的zrange拿出前面排名的 if err != nil { return visit, err } if len(res) != len(miss) { return visit, errors.New(fmt.Sprintf("MGetRoomVisitCount fail,miss match len,%v-%v", len(res), len(miss))) } for i, groupId := range miss { if cnt, ok := res[i].(string); ok { visit[groupId] = cnt _ = roomVisitCntCache.SetWithExpire(groupId, cnt, time.Minute*15) } } return visit, nil } func GetSetRoomVisitCount(groupId string) (int64, error) { key := redis_key.GetPrefixGroupInUserDuration(groupId) vc, err := redisCli.GetRedis().ZCard(context.Background(), key).Result() // 查到合法值后,更新二级缓存 if err == nil && vc >= 0 { if ret, err := saveRoomVisitCount(groupId, vc); err != nil { mylogrus.MyLog.Errorf("saveRoomVisitCount %s, ret = %d, err: %v", groupId, ret, err) } } return vc, err } func saveRoomVisitCount(groupId string, count int64) (int64, error) { key := redis_key.GetPrefixRoomVisitCount() zKey := redis_key.GetPrefixRoomVisitCountZset() // zset同步存一份到redis集群 if err := redisCli.GetClusterRedis().ZAdd(context.Background(), zKey, &redis2.Z{ Score: float64(count), Member: groupId, }).Err(); err != nil { mylogrus.MyLog.Errorf("GetPrefixRoomVisitCountZset fail %s", err.Error()) } return redisCli.GetRedis().HSet(context.Background(), key, groupId, strconv.FormatInt(count, 10)).Result() } func clearRoomVisit(groupId string, t time.Time) (int64, error) { value := strconv.FormatInt(t.Unix(), 10) ret, err := redisCli.GetRedis().ZRemRangeByScore(context.Background(), redis_key.GetPrefixGroupInUserDuration(groupId), "0", value).Result() if err != nil { return 0, err } return ret, nil } // Deprecated: hgetall有问题 func GetAllRoomVisitCount() (map[string]string, error) { key := redis_key.GetPrefixRoomVisitCount() return redisCli.GetRedis().HGetAll(context.Background(), key).Result() }