using System; using System.Collections.Generic; using System.Collections.Concurrent; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using ChessGameDomain; using Common.Redis; using CommonDomain; using CommonDomain.BaseModel; using RedisHelper; using RedisService.Param; using UserDomain.Entity; namespace RedisService { public class RedisService : IRedisService { private readonly ICache _cache; private static readonly ConcurrentDictionary GameRoomCache = new(); private static readonly TimeSpan GameRoomReadCacheDuration = TimeSpan.FromSeconds(3); public RedisService(ICache cache) { _cache = cache; } public RedisUserCid GetRedisUserCId(string userId) { return _cache.Get(string.Format(RedisKey.UserCIDGID, userId)); } public void SetRedisUserCId(RedisUserCid redisUser) { _cache.Insert(string.Format(RedisKey.UserCIDGID, redisUser.UserId), redisUser); } public void RemoveRedisUserCId(string userId) { _cache.Remove(string.Format(RedisKey.UserCIDGID, userId)); } private static readonly ConcurrentDictionary UserIdCache = new(); public string GetUserId(string cid) { UserIdCache.TryGetValue(cid, out var userId); return userId; } public void SetUserId(string cid, string userId) { UserIdCache[cid] = userId; } public void RemoveUserId(string cid) { UserIdCache.TryRemove(cid, out _); } public string GetLoginUserId(string cid) { return _cache.Get(string.Format(RedisKey.LoginCIDUser, cid)); } public void SetLoginUserId(string cid, string userId) { _cache.Insert(string.Format(RedisKey.LoginCIDUser, cid), userId); } public IEnumerable GetAllLoginUserIds() { var list = _cache.GetPatternList(string.Format(RedisKey.LoginCIDUser, "*"), 100000); return list; } public void RemoveGameConfig() { _cache.Remove(RedisKey.GameConfig); } public void SetActivityConfig(ActivityConfig config) { _cache.Insert(RedisKey.ActivityConfig, config); } public ActivityConfig GetActivityConfig() { return _cache.Get(RedisKey.ActivityConfig); } public void RemoveActivityConfig() { _cache.Remove(RedisKey.ActivityConfig); } private static string PlayerGoldKey(string roomId, string userId) => $"gold:{roomId}:{userId}"; private static string PlayerBulletsKey(string roomId, string userId) => $"bullets:{roomId}:{userId}"; private static string PlayerFactorKey(string roomId, string userId) => $"factor:{roomId}:{userId}"; private static string RoomKillFishKey(string roomId) => $"killfish:{roomId}"; private static string FishingTaskCountKey(string roomId, string userId, int taskEvent) => $"fishing:tasks:{roomId}:{userId}:{taskEvent}"; private static string FishingConsumeKey(string roomId, string userId) => $"fishing:consume:runtime:{roomId}:{userId}"; private static string FishingExpKey(string roomId, string userId) => $"fishing:exp:runtime:{roomId}:{userId}"; public long GetPlayerGold(string roomId, string userId) { return _cache.Get(PlayerGoldKey(roomId, userId)); } public void SetPlayerGold(string roomId, string userId, long gold) { _cache.Insert(PlayerGoldKey(roomId, userId), gold); } public bool AddBulletId(string roomId, string userId, string bulletId) { return _cache.SetAdd(PlayerBulletsKey(roomId, userId), bulletId); } public bool ExistsBulletId(string roomId, string userId, string bulletId) { return _cache.SetContains(PlayerBulletsKey(roomId, userId), bulletId); } public bool RemoveBulletId(string roomId, string userId, string bulletId) { return _cache.SetRemove(PlayerBulletsKey(roomId, userId), bulletId); } public long GetBulletCount(string roomId, string userId) { return _cache.SetCount(PlayerBulletsKey(roomId, userId)); } public void ClearBulletIds(string roomId, string userId) { _cache.Remove(PlayerBulletsKey(roomId, userId)); } public void ClearPlayerRuntimeData(string roomId, string userId) { _cache.Remove(PlayerGoldKey(roomId, userId)); _cache.Remove(PlayerBulletsKey(roomId, userId)); _cache.Remove(PlayerFactorKey(roomId, userId)); } public void AddFishingTaskProgress(string roomId, string userId, int taskEvent, long count) { if (count <= 0) return; _cache.IncrBy(FishingTaskCountKey(roomId, userId, taskEvent), count); } public Dictionary GetFishingTaskProgress(string roomId, string userId, IEnumerable taskEvents) { var result = new Dictionary(); foreach (var taskEvent in taskEvents.Distinct()) { var count = _cache.Get(FishingTaskCountKey(roomId, userId, taskEvent)); if (count > 0) result[taskEvent] = count; } return result; } public void ClearFishingTaskProgress(string roomId, string userId, IEnumerable taskEvents) { foreach (var taskEvent in taskEvents.Distinct()) _cache.Remove(FishingTaskCountKey(roomId, userId, taskEvent)); } public void AddFishingConsumeProgress(string roomId, string userId, long count) { if (count > 0) _cache.IncrBy(FishingConsumeKey(roomId, userId), count); } public long GetFishingConsumeProgress(string roomId, string userId) => _cache.Get(FishingConsumeKey(roomId, userId)); public void AddFishingExpProgress(string roomId, string userId, long count) { if (count > 0) _cache.IncrBy(FishingExpKey(roomId, userId), count); } public long GetFishingExpProgress(string roomId, string userId) => _cache.Get(FishingExpKey(roomId, userId)); public void ClearFishingRuntimeProgress(string roomId, string userId) { _cache.Remove(FishingConsumeKey(roomId, userId)); _cache.Remove(FishingExpKey(roomId, userId)); } public PlayerFactor GetPlayerFactor(string roomId, string userId) { return _cache.Get(PlayerFactorKey(roomId, userId)); } public void SetPlayerFactor(string roomId, string userId, PlayerFactor factor) { _cache.Insert(PlayerFactorKey(roomId, userId), factor); } public void RemovePlayerFactor(string roomId, string userId) { _cache.Remove(PlayerFactorKey(roomId, userId)); } public List GetKillFishIds(string roomId) { return _cache.SetMembers(RoomKillFishKey(roomId)); } public void AddKillFishId(string roomId, string fishId) { _cache.SetAdd(RoomKillFishKey(roomId), fishId); } public bool ContainsKillFishId(string roomId, string fishId) { return _cache.SetContains(RoomKillFishKey(roomId), fishId); } public List GetAllPlayingChessRooms() { var allRooms = GetAllChessRooms(); if (allRooms == null) return new List(); return allRooms.Where(r => r.state == 2).ToList(); } public void SetFishingKillConfig(FishingKillConfig config) { _cache.Insert(RedisKey.FishingKillConfig, config); } public FishingKillConfig GetFishingKillConfig() { return _cache.Get(RedisKey.FishingKillConfig); } public void SetFishSpawnConfig(string json) { _cache.Insert(RedisKey.FishSpawnConfig, json); } public string GetFishSpawnConfig() { return _cache.Get(RedisKey.FishSpawnConfig); } public void SetGameRoom(RedisGameRoom gameRoom) { string Partition = $"{(int)gameRoom.GameType}{gameRoom.RoomLevel}{gameRoom.RoomPartition}"; _cache.Insert(string.Format(RedisKey.GameRoomIdKey, Partition, gameRoom.RoomId), gameRoom); GameRoomCache[gameRoom.RoomId] = new RoomCacheEntry(gameRoom, DateTime.UtcNow, true); } public RedisGameRoom GetGameRoom(string roomId) { if (string.IsNullOrWhiteSpace(roomId)) return null; var partition = roomId.Length >= 3 ? roomId.Substring(0, 3) : roomId.PadRight(3, '0'); var room = _cache.Get(string.Format(RedisKey.GameRoomIdKey, partition, roomId)); if (room != null) GameRoomCache[roomId] = new RoomCacheEntry(room, DateTime.UtcNow, false); else GameRoomCache.TryRemove(roomId, out _); return room; } public IEnumerable GetGameRoomList(string partition) { var list = _cache.GetPatternList(string.Format(RedisKey.GameRoomIdKey, partition, "*"), 100); return list; } public IEnumerable GetGameRoomAllList() { var list = _cache.GetPatternList(string.Format(RedisKey.GameRoomIdKey, "*", "*"), 10000); return list; } public string GetPendingFishRoomId(string userId) { if (string.IsNullOrWhiteSpace(userId)) return string.Empty; var rooms = GetGameRoomAllList(); if (rooms == null) return string.Empty; var room = rooms.FirstOrDefault(r => r != null && r.Players != null && r.Players.Any(p => p.UserId == userId && !p.IsBot)); return room?.RoomId ?? string.Empty; } public void RemoveGameRoom(string partition) { _cache.Clear(string.Format(RedisKey.GameRoomIdKey, partition, "*")); foreach (var roomId in GameRoomCache.Keys.Where(id => id.StartsWith(partition, StringComparison.Ordinal))) GameRoomCache.TryRemove(roomId, out _); } public void RemoveGameRoomAll() { _cache.Clear(string.Format(RedisKey.GameRoomIdKey, "*", "*"), 50000); GameRoomCache.Clear(); } private sealed record RoomCacheEntry(RedisGameRoom Room, DateTime CachedAt, bool IsLocallyOwned); public void SetGameConfig(GameConfig gameConfig) { _cache.Insert(RedisKey.GameConfig, gameConfig); } public GameConfig GetGameConfig() { return _cache.Get(RedisKey.GameConfig); } public void SetSystemGoldDay(long amount) { _cache.Insert(RedisKey.SystemGoldDayKey, amount); } public void AddSystemGoldDay(long gold) { _cache.IncrBy(RedisKey.SystemGoldDayKey, gold); } public long GetSystemGoldDay() { return _cache.Get(RedisKey.SystemGoldDayKey); } public void SetChessRoom(ChessGameRoom room) { string key = string.Format(RedisKey.ChessRoomKey, room.RoomId); _cache.Insert(key, room); } public ChessGameRoom GetChessRoom(string roomId) { string key = string.Format(RedisKey.ChessRoomKey, roomId); return _cache.Get(key); } public List GetAllChessRooms() { var pattern = RedisKeyGenerator.GameKey("chess:room:*"); return _cache.GetPatternList(pattern, 10000) ?.Select(r => r ?? new ChessGameRoom()) .ToList() ?? new List(); } public string GetPendingChessRoomId(string userId) { if (string.IsNullOrWhiteSpace(userId)) return string.Empty; var rooms = GetAllChessRooms(); if (rooms == null || rooms.Count == 0) return string.Empty; var room = rooms.FirstOrDefault(r => r != null && r.state == 2 && !r.IsGameEnded && r.users != null && r.users.Any(u => u.userId == userId)); return room?.RoomId ?? string.Empty; } public void RemoveChessRoom(string roomId) { string key = string.Format(RedisKey.ChessRoomKey, roomId); _cache.Remove(key); } public void ClearAllChessRooms() { var pattern = RedisKeyGenerator.GameKey("chess:room:*"); _cache.Clear(pattern, 50000); } public void ClearAllGameRooms() { var pattern = RedisKeyGenerator.GameKey("room:model:*"); _cache.Clear(pattern, 50000); } public void ClearAllUserMappings() { var cidPattern = RedisKeyGenerator.UserKey("cid:*"); var uidPattern = RedisKeyGenerator.UserKey("uid:*"); _cache.Clear(cidPattern, 50000); _cache.Clear(uidPattern, 50000); } public void ClearAllLoginUserIds() { var cidPattern = RedisKeyGenerator.UserKey("cid:*"); var uidPattern = RedisKeyGenerator.UserKey("uid:*"); _cache.Clear(cidPattern, 100000); _cache.Clear(uidPattern, 100000); } public void RemoveLoginUserId(string cid) { _cache.Remove(RedisKey.LoginCIDUser.Replace("{0}", cid)); } public void SetVerificationCode(string phone, string code) { _cache.Insert(RedisKey.VerificationCode.Replace("{0}", phone), code, TimeSpan.FromMinutes(5)); } public string GetVerificationCode(string phone) { return _cache.Get(RedisKey.VerificationCode.Replace("{0}", phone)); } public void RemoveVerificationCode(string phone) { _cache.Remove(RedisKey.VerificationCode.Replace("{0}", phone)); } public long IncrBy(string key, long value) { return _cache.IncrBy(key, value); } public string GetString(string key) { return _cache.Get(key); } public void SetString(string key, string value) { _cache.Insert(key, value); } } }