using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.DataProtection.KeyManagement; using Microsoft.AspNetCore.Identity; using Nettention.Proud; using Newtonsoft.Json; using OtpNet; using Pipelines.Sockets.Unofficial.Buffers; using StackExchange.Redis; using ServerCore; using ServerBase; using SESSION_ID = System.Int32; using META_ID = System.UInt32; using ENTITY_GUID = System.String; using ACCOUNT_ID = System.String; using OWNER_GUID = System.String; using USER_GUID = System.String; using CHARACTER_GUID = System.String; using ITEM_GUID = System.String; namespace ServerCommon; public static class ServerConnectionSwitchHelper { public static async Task registerUserOtpToTargetServer(UserBase entityUser, RedisConnector redisConnector , string destServer) { var result = new Result(); var err_msg = string.Empty; (result, var reserved_to_switch_server) = await startServerSwitch(entityUser, redisConnector, destServer); if (result.isFail()) { return result; } NullReferenceCheckHelper.throwIfNull(reserved_to_switch_server, () => $"reserved_to_switch_server is null !!!"); var account_attribute = entityUser.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!! - {entityUser.toBasicString()}"); account_attribute.OtpForServerConnect = reserved_to_switch_server.OneTimeKey; return result; } public static async Task<(Result, LoginCache.ReservationToSwitchServer?)> startServerSwitch(UserBase entityUser, RedisConnector redisConnector, string destServer) { var result = new Result(); var err_msg = string.Empty; try { var login_cache_request = new LoginCacheRequest(entityUser, redisConnector); result = await login_cache_request.onPrepareRequest(); if (result.isFail()) { return (result, null); } string key = login_cache_request.getKey(); var database = login_cache_request.getDatabase(); var value = await database.StringGetAsync(key, CommandFlags.PreferReplica); if (value.HasValue == false) { err_msg = $"Not found Key !!! : Key:{key} - {entityUser.toBasicString()}"; result.setFail(ServerErrorCode.RedisLoginCacheGetFailed, err_msg); Log.getLogger().error(result.toBasicString()); return (result, null); } var login_cache = JsonConvert.DeserializeObject(value.ToString()); if (null == login_cache) { err_msg = $"Failed to JsonConvert.DeserializeObject !!! : {login_cache_request.toBasicString()} - {entityUser.toBasicString()}"; result.setFail(ServerErrorCode.JsonConvertDeserializeFailed, err_msg); Log.getLogger().error(result.toBasicString()); return (result, null); } var otp = KeyGeneration.GenerateRandomKey(20); var otp_encoding_by_base32 = Base32Encoding.ToString(otp); login_cache.ReservedToSwitchServer = new LoginCache.ReservationToSwitchServer() { OneTimeKey = otp_encoding_by_base32, DestServer = destServer }; var json_string = login_cache.toJsonString(); if (await database.StringSetAsync(key, json_string, TimeSpan.FromMilliseconds(LoginCacheRequest.SERVER_SWITCH_CACHE_EXPIRY_TIME)) == false) { err_msg = $"Failed to StringSetAsync !!! : Key:{key}, JsonString:{json_string} - {entityUser.toBasicString()}"; result.setFail(ServerErrorCode.RedisStringsWriteFailed, err_msg); Log.getLogger().error(result.toBasicString()); return (result, null); } Log.getLogger().info($"Server Switching Start : currServer:{login_cache.CurrentServer}, destServer:{destServer} - {entityUser.toBasicString()}"); return (result, login_cache.ReservedToSwitchServer); } catch (Exception e) { err_msg = $"Failed to startServerSwitch !!! : Exception:{e} - {entityUser.toBasicString()}"; result.setFail(ServerErrorCode.TryCatchException, err_msg); Log.getLogger().error(result.toBasicString()); return (result, null); } } public static async Task endServerSwitch(EntityBase entityUser, LoginCacheRequest loginCacheRequest , string currConnectedServer , DateTime switchedDateTime) { var result = new Result(); var err_msg = string.Empty; try { var database = loginCacheRequest.getDatabase(); var login_cache = loginCacheRequest.getLoginCache(); NullReferenceCheckHelper.throwIfNull(login_cache, () => $"login_cache is null !!!"); NullReferenceCheckHelper.throwIfNull(login_cache.ReservedToSwitchServer, () => $"login_cache.ReservedToSwitchServer is null !!!"); string prev_connected_server = login_cache.CurrentServer; login_cache.LoginDateTime = switchedDateTime; login_cache.ServerSwitchCount += 1; login_cache.CurrentServer = login_cache.ReservedToSwitchServer.DestServer; login_cache.ReservedToSwitchServer = null; var key = loginCacheRequest.getKey(); var json_string = login_cache.toJsonString(); if (await database.StringSetAsync(key, json_string, TimeSpan.FromMilliseconds(LoginCacheRequest.LOGIN_CACHE_EXPIRY_TIME)) == false) { err_msg = $"Failed to StringSetAsync !!! : Key:{key}, JsonString:{json_string} - {entityUser.toBasicString()}"; result.setFail(ServerErrorCode.RedisStringsWriteFailed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } Log.getLogger().info($"Server Switching End : prevServer:{prev_connected_server} => currServer:{currConnectedServer} - {entityUser.toBasicString()}"); return result; } catch (Exception e) { err_msg = $"Failed to startServerSwitch !!! : Exception:{e} - {entityUser.toBasicString()}"; result.setFail(ServerErrorCode.TryCatchException, err_msg); Log.getLogger().error(result.toBasicString()); return result; } } }