using Google.Protobuf.WellKnownTypes; using Newtonsoft.Json; using StackExchange.Redis; using ServerCore; using ServerBase; namespace ServerCommon; public class SummonInfo { // 소환 여부 판단 ( true - 소환 중 ) public bool IsAlreadySummon { get; set; } // 소환 Server public string? SummonServer { get; set; } // 소환 Pos public Pos? SummonPos { get; set; } public SummonInfo clone() { var clone = new SummonInfo { IsAlreadySummon = IsAlreadySummon, SummonServer = SummonServer, SummonPos = SummonPos }; return clone; } public void clear() { IsAlreadySummon = false; SummonServer = null; SummonPos = null; } } public class PartyMemberInfo { // 유저 Guid public string UserGuid { get; set; } = string.Empty; // 유저 nickname ( 파티 도중 닉네임 변경시 처리 불가 public string Nickname { get; set; } = string.Empty; // 마커 Id - 유저 표시용 public int MarkId { get; set; } = 0; // Party Join Time public Timestamp JoinTime { get; set; } = new(); // 소환 정보 public SummonInfo Summon { get; set; } = new(); // 유저 위치 정보 public UserLocationInfo LocationInfo { get; set; } = new(); public PartyMemberInfo clone() { var clone = new PartyMemberInfo { UserGuid = UserGuid, Nickname = Nickname, MarkId = MarkId, JoinTime = JoinTime, Summon = Summon.clone(), LocationInfo = LocationInfo }; return clone; } } public class PartyMemberCache : CacheBase { public Dictionary PartyMembers { get; set; } = new(); public void upsertPartyMember(PartyMemberInfo user) { PartyMembers[user.UserGuid] = user; } public void deleteJoinMember(string user_guid) => PartyMembers.Remove(user_guid); public string toBasicString() { return $"PartyCache: PartyMembers:{PartyMembers}"; } } public class PartyMemberCacheRequest : RedisRequestSharedBase { // in private readonly string m_party_guid; // out private PartyMemberCache? m_party_member_cache_nullable { get; set; } public PartyMemberCacheRequest(string party_guid, RedisConnector redisConnector) : base(party_guid, redisConnector) { m_party_guid = party_guid; } protected override string onMakeKey() => $"party:{m_party_guid}:members"; public override string toBasicString() => $"PartyMemberCache: In:PartyGuid:{m_party_guid}, Out:{m_party_member_cache_nullable?.toBasicString()}"; public PartyMemberCache? getPartyMemberCache() => m_party_member_cache_nullable; public async Task keepPartyMemberCache() { var result = new Result(); string err_msg; try { result = await onPrepareRequest(); if (result.isFail()) return result; var database = getDatabase(); ArgumentNullException.ThrowIfNull(database); var redis_value = await database.KeyExpireAsync(getKey(), TimeSpan.FromMilliseconds(Constant.KEEP_PARTY_TIME)); if (false == redis_value) { err_msg = $"Failed to set expire PartyMemberCache in Redis !!! : Key:{getKey()} - {nameof(keepPartyMemberCache)}"; result.setFail(ServerErrorCode.RedisGlobalPartyMemberCacheWriteFailed, err_msg); Log.getLogger().error(err_msg); } } catch (Exception e) { var error_code = ServerErrorCode.TryCatchException; err_msg = $"Failed to set expire PartyMemberCache from Redis !!! : : errorCode{error_code}, errMsg:{e.Message} - {nameof(keepPartyMemberCache)}"; result.setFail(error_code, err_msg); Log.getLogger().error(err_msg); } return result; } public async Task fetchPartyMemberCache() { var result = new Result(); string err_msg; try { result = await onPrepareRequest(); if (result.isFail()) return result; var database = getDatabase(); ArgumentNullException.ThrowIfNull(database); var curr_party_members = new List(); var redis_value = await database.HashValuesAsync(getKey(), CommandFlags.PreferReplica); foreach (var member_value in redis_value) { var member = JsonConvert.DeserializeObject(member_value.ToString()); if (null == member) { Log.getLogger().error($"JsonConvert.DeserializeObject Error {member_value.ToString()}"); continue; } curr_party_members.Add(member); } m_party_member_cache_nullable ??= new PartyMemberCache(); m_party_member_cache_nullable.PartyMembers.Clear(); foreach (var member in curr_party_members) { m_party_member_cache_nullable.PartyMembers.Add(member.UserGuid, member); } return result; } catch (Exception e) { var error_code = ServerErrorCode.TryCatchException; err_msg = $"Failed to get PartyMemberCache from Redis !!! : : errorCode{error_code}, errMsg:{e.Message} - {nameof(fetchPartyMemberCache)}"; result.setFail(error_code, err_msg); Log.getLogger().error(err_msg); } return result; } public async Task changeJoinMember(PartyMemberInfo user) { var result = new Result(); string err_msg; try { result = await onPrepareRequest(); if (result.isFail()) return result; var database = getDatabase(); ArgumentNullException.ThrowIfNull(database); var input_user_json = JsonConvert.SerializeObject(user); await database.HashSetAsync(getKey(), user.UserGuid, input_user_json); m_party_member_cache_nullable ??= new PartyMemberCache(); m_party_member_cache_nullable.upsertPartyMember(user); result = await keepPartyMemberCache(); return result; } catch (Exception e) { var error_code = ServerErrorCode.TryCatchException; err_msg = $"Failed to get PartyMemberCache from Redis !!! : : errorCode{error_code}, errMsg:{e.Message} - {nameof(fetchPartyMemberCache)}"; result.setFail(error_code, err_msg); Log.getLogger().error(err_msg); } return result; } public async Task deletePartyMemberCache() { var result = new Result(); try { result = await onPrepareRequest(); if (result.isFail()) return result; var database = getDatabase(); ArgumentNullException.ThrowIfNull(database); m_party_member_cache_nullable = null; _ = await database.KeyDeleteAsync(getKey(), CommandFlags.FireAndForget); return result; } catch (Exception e) { var error_code = ServerErrorCode.TryCatchException; var err_msg = $"Failed to delete PartyMemberCache from Redis !!! : : errorCode{error_code}, errMsg:{e.Message} - {nameof(deletePartyMemberCache)}"; result.setFail(error_code, err_msg); Log.getLogger().error(err_msg); } return result; } public async Task deleteJoinMember(string delete_user) { var result = new Result(); string err_msg; try { result = await onPrepareRequest(); if (result.isFail()) return result; var database = getDatabase(); ArgumentNullException.ThrowIfNull(database); if (false == await database.HashDeleteAsync(getKey(), delete_user)) { err_msg = $"Fail to delete join member !!! : {nameof(changeJoinMember)} - user_guid[{delete_user}]"; result.setFail(ServerErrorCode.RedisSetsWriteFailed, err_msg); Log.getLogger().error(err_msg); return result; } if (null == m_party_member_cache_nullable) { return result; } m_party_member_cache_nullable.deleteJoinMember(delete_user); return result; } catch (Exception e) { var error_code = ServerErrorCode.TryCatchException; err_msg = $"Failed to delete PartyMemberCache from Redis !!! : : errorCode{error_code}, errMsg:{e.Message} - {nameof(deleteJoinMember)}"; result.setFail(error_code, err_msg); Log.getLogger().error(err_msg); } return result; } }