using Newtonsoft.Json; using ServerCore; using ServerBase; using ServerCommon; using static ServerCommon.MetaHelper; using META_ID = System.UInt32; using Amazon.S3.Model; namespace GameServer { public class AIChatAction : EntityActionBase { private string user_jwt = string.Empty; public AIChatAction(Player owner) : base(owner) { } public override Task onInit() { var result = new Result(); return Task.FromResult(result); } public override void onClear() { user_jwt = string.Empty; } //-------------인증 JWT 관련 API------------- //특정 유저의 JWT를 검증합니다. public async Task<(Result, AIChatJwtInfo?)> jwtverify(string user_jwt) { var result = new Result(); var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var server_logic = GameServerApp.getServerLogic(); if (server_logic.getServerConfig().OfflineMode == true) { result.setFail(ServerErrorCode.AiChatServerInactive); return (result, null); } var url = $"/api/auth/jwt/verify"; (result, string resMsg) = await AIChatServerConnector.sendAIChatServer("GET", url, user_jwt, null); if (result.isFail()) { Log.getLogger().error($"Failed ai chat server action : jwtverify, msg : {resMsg}"); return (result, null); } var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatJwtVerify); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); try { var aichat_jwt_info = JsonConvert.DeserializeObject(resMsg); return (result, aichat_jwt_info); } catch(Exception ex) { Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}"); return (result, null); } } //특정 유저의 JWT를 발행합니다. public async Task<(Result, string?)> jwtIssue(string user_guid) { var result = new Result(); var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var server_logic = GameServerApp.getServerLogic(); if (server_logic.getServerConfig().OfflineMode == true) { result.setFail(ServerErrorCode.AiChatServerInactive); return (result, string.Empty); } var url = $"/api/auth/jwt/issue/{user_guid}"; var body = AIChatServerConnector.getUserJwtJson(); (result, string resMsg) = await AIChatServerConnector.sendAIChatServer("POST", url, null, body); if (result.isFail()) { Log.getLogger().error($"Failed ai chat server action : jwtIssue, msg : {resMsg}"); return (result, string.Empty); } var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatJwtIssue); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); try { var ai_chat_issue_jwt = JsonConvert.DeserializeObject(resMsg); NullReferenceCheckHelper.throwIfNull(ai_chat_issue_jwt, () => $"ai_chat_issue_jwt is null !!! - {toBasicString()}"); user_jwt = ai_chat_issue_jwt.jwt == null ? string.Empty : ai_chat_issue_jwt.jwt; return (result, user_jwt); } catch (Exception ex) { Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}"); return (result, null); } } //포인트 충전 public async Task pointCharge(AIChatPointCharge aIChatPointCharge) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var url = $"/api/point/charge"; var body = JsonConvert.SerializeObject(aIChatPointCharge); (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("PUT", url, body); if (result.isFail()) { if (result.ErrorCode == ServerErrorCode.AiChatServerInactive) return result; result.setFail(ServerErrorCode.AiChatServerRetryChargePoint); Log.getLogger().error($"Failed ai chat server action : pointCharge, msg : {resMsg}"); return result; } var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatPointCharge); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } //포인트 충전 확인 public async Task pointChargeCheckByOrderGuid(string order_guid) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var aIPointVerify = new AIChatPointVerify() { orderGuid = order_guid }; var url = $"/api/point/charge"; var body = JsonConvert.SerializeObject(aIPointVerify); (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("GET", url, body); if (result.isFail()) return result; var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatPointChargeVerify); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } //어제까지의 벌어들인 미청구 포인트 조회 public async Task<(Result, AIChatPointClaimables?)> pointClaimables(int page, int num_per_page, string user_guid) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var url = $"/api/point/claimables/{user_guid}?page={page}&numPerPage={num_per_page}"; (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("GET", url, null); if (result.isFail()) { if (result.ErrorCode == ServerErrorCode.AiChatServerUserNotFound) { result = await registerUser(player.getUserGuid(), player.getUserNickname()); if (result.isFail()) { return (result, null); } (result, resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("GET", url, null); if (result.isFail()) { return (result, null); } } } var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatIncentiveSearch); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); try { var aichat_point_claim_ables = JsonConvert.DeserializeObject(resMsg); return (result, aichat_point_claim_ables); } catch (Exception ex) { Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}"); return (result, null); } } //인센티브 수령 완료 표시 public async Task pointMarkClaimed(string user_guid, int marking_day) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"server_logic is null !!!"); var url = $"/api/point/mark-as-claimed/{user_guid}?aggregationEndTime={marking_day}"; (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("POST", url, null); if (result.isFail()) { Log.getLogger().error($"Failed ai chat server action : pointMarkClaimed, msg : {resMsg}"); return result; } var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatIncentiveMarking); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } //신규 유저 등록 public async Task registerUser(string user_guid, string name) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var url = $"/api/user/{user_guid}"; var aIRegisterUser = new AIChatRegisterUser() { nick = name }; var body = JsonConvert.SerializeObject(aIRegisterUser); (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("POST", url, body); if (result.isFail()) { Log.getLogger().error($"Failed ai chat server action : registerUser, user_guid : {user_guid}, name : {name}, msg : {resMsg}"); return result; } var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatRegisterUser); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } //유저 등록 제거 public async Task deleteUser(string user_guid) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var url = $"/api/user/{user_guid}"; (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("DELETE", url, null); if (result.isFail()) return result; var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatDeleteUser); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } //특정 캐릭터 조회 public async Task<(Result, AIChatCharacter?)> getCharacterByTargetGuid(string target_guid) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var url = $"/api/character/{target_guid}"; (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("GET", url, null); if (result.isFail()) return (result, null); var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatGetCharacter); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); try { var aichat_character = JsonConvert.DeserializeObject(resMsg); return (result, aichat_character); } catch (Exception ex) { Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}"); return (result, null); } } //-------------유저 권한 API------------- //신규 캐릭터 등록 public async Task registerCharacter(AIChatRegisterCharacter aIChatRegisterCharacter) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var url = $"/api/character"; var body = JsonConvert.SerializeObject(aIChatRegisterCharacter); (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("POST", url, body); if (result.isFail()) { Log.getLogger().error($"Failed ai chat server action : registerCharacter, msg : {resMsg}"); return result; } var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatRegisterCharacter); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } //캐릭터 수정 public async Task updateCharacter(AIChatRegisterCharacter aIChatRegisterCharacter) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var url = $"/api/character/locale/{aIChatRegisterCharacter.guid}"; var body = JsonConvert.SerializeObject(aIChatRegisterCharacter); (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("PUT", url, body); if (result.isFail()) return result; var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatUpdateCharacter); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } //캐릭터 등록 제거 public async Task deleteCharacter(string character_guid) { var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var url = $"/api/character/{character_guid}"; (var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("DELETE", url, null); if (result.isFail()) return result; var invokers = new List(); var log_action = new LogActionEx(LogActionType.AIChatDeleteCharacter); var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty); invokers.Add(new AIChatBusinessLog(task_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } /// /// 데이터 수집 기간 : 월요일 00:00:00 ~ 일요일 23:59:59(KST 기준 - UTC+9) /// 인센티브 보상 지급 날짜 및 시각 : 매주 월요일 05:00 (KST 기준 - UTC+9) /// public async Task updateTickOfIncentivePoint() { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var current_time = DateTimeHelper.Current; var incentive_collect_time = current_time.AddDays(Convert.ToInt32(DayOfWeek.Monday) - Convert.ToInt32(current_time.DayOfWeek)).Date; var incentive_provide_time = incentive_collect_time.AddHours(5); var ai_chat_attribute = player.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(ai_chat_attribute, () => $"ai_chat_attribute is null !!! - {player.toBasicString()}"); var last_incentive_provide_time = ai_chat_attribute.LastIncentiveProvideTime; if (last_incentive_provide_time != default || last_incentive_provide_time == incentive_provide_time || incentive_provide_time > current_time) { return result; } result = await TakeIncentivePoint(incentive_provide_time); if(result.isFail()) return result; return result; } public async Task TakeIncentivePoint(DateTime new_incentive_provide_time) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var server_logic = GameServerApp.getServerLogic(); var dynamo_db_client = server_logic.getDynamoDbClient(); var mail_action = player.getEntityAction(); NullReferenceCheckHelper.throwIfNull(mail_action, () => $"mail_action is null !!!"); var ai_chat_attribute = player.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(ai_chat_attribute, () => $"ai_chat_attribute is null !!! - {player.toBasicString()}"); if (MetaData.Instance._CurrencyMetaTableByCurrencyType.TryGetValue(CurrencyType.Beam, out var currencyMetaData) == false) { result.setFail(ServerErrorCode.CurrencyNotFoundData, err_msg); return result; } (result, var pointClaim) = await pointClaimables(0, 100, player.getUserGuid()); if (result.isFail()) { return result; } NullReferenceCheckHelper.throwIfNull(pointClaim, () => $"pointClaim is null !!! - {toBasicString()}"); if (pointClaim.items.Count == 0) { ai_chat_attribute.LastIncentiveProvideTime = new_incentive_provide_time; ai_chat_attribute.modifiedEntityAttribute(); (result, var ai_chat_doc) = await ai_chat_attribute.toDocBase(); if (result.isFail()) return result; NullReferenceCheckHelper.throwIfNull(ai_chat_doc, () => $"ai_chat_doc is null !!! - {player.toBasicString()}"); result = await dynamo_db_client.simpleUpdateDocumentWithDocType(ai_chat_doc); if (result.isFail()) { err_msg = $"Failed to simpleUpdateDocumentWithDocType ai_chat_doc !!! - {player.toBasicString()}"; Log.getLogger().error(err_msg); return result; } return result; } var IncentivePointList = new List(); int maxPoint = GameConfigMeta.AiChatInsentiveMax; int last_incentive_period = 0; foreach (var pointInfo in pointClaim.items) { int amount = pointInfo.amount; if(maxPoint < amount) { amount = maxPoint; } IncentivePointList.Add(amount); if(last_incentive_period < pointInfo.end_time) { last_incentive_period = pointInfo.end_time; } } var fn_send_system_mail = async delegate () { var result = new Result(); var err_msg = string.Empty; var receivedMailDocs = new List(); foreach (var amount in IncentivePointList) { var mail_items = new List() { new ServerCommon.MailItem() { ItemId = (META_ID)currencyMetaData.ItemId, Count = amount } }; (result, var receivedMailDoc) = await mail_action.tryMakeNewSystemMail(mail_items, ServerCommon.Constant.NPC_INSENTIVE_META_KEY, GameConfigMeta.AiChatInsentivePeriod, string.Empty); if (result.isFail()) { return result; } NullReferenceCheckHelper.throwIfNull(receivedMailDoc, () => $"receivedMailDoc is null !!! - {toBasicString()}"); receivedMailDocs.Add(receivedMailDoc); } ai_chat_attribute.LastIncentiveProvideTime = new_incentive_provide_time; var batch = new QueryBatchEx(player, LogActionType.MailAiChatIncentivePoint , dynamo_db_client); { batch.addQuery(new DBQEntityWrite(receivedMailDocs)); batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { return result; } result = await pointMarkClaimed(player.getUserGuid(), last_incentive_period); if (result.isFail()) { return result; } mail_action.NewReceivedMail(); return result; }; var transaction_name = "provideIncentivePoint"; result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid() , TransactionIdType.PrivateContents, transaction_name , fn_send_system_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - transactionName:{transaction_name}, {player.toBasicString()}"; Log.getLogger().error(err_msg); } return result; } } }