using System.Collections.Concurrent; using Google.Protobuf; using Google.Protobuf.WellKnownTypes; using ServerCore; using ServerBase; using ServerCommon; using static ClientToGameReq.Types; using static ClientToGameRes.Types; using ALERT_KEY = System.String; namespace GameServer; public class EntityAlertAction : EntityActionBase { public delegate Task<(Result, List, EntityAlertMethodType)> FnAlertFunction(EntityAlertTriggerType triggerType); private ConcurrentDictionary m_alert_functions = new(); private ConcurrentDictionary m_alert_toggles = new(); // true일 경우 알림 트리거 활성화 !!! public EntityAlertAction(EntityBase owner) : base(owner) { } public override Task onInit() { return Task.FromResult(new Result()); } public override void onClear() { } public async Task onApplyEntityAlertType() { var owner = getOwner(); NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var err_msg = string.Empty; var result = new Result(); if(0 >= m_alert_functions.Count) { return; } await loadEntityAlertRecordFromDb(); } private async Task loadEntityAlertRecordFromDb() { var owner = getOwner(); NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var server_logic = GameServerApp.getServerLogic(); var dynamo_db_connector = server_logic.getDynamoDbClient(); var err_msg = string.Empty; var result = new Result(); if (false == owner.isValidOwnerEntityTypeWithGuid()) { err_msg = $"Invalid Owner !!! : ownerType:{owner.onGetOwnerEntityType()}, ownerGuid:{owner.onGetGuidOfOwnerEntityType()} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.OwnerInvalid, err_msg); Log.getLogger().error(result.toBasicString()); return result; } foreach (var each in m_alert_functions) { var trigger_type = each.Key; var owner_guid = owner.onGetGuidOfOwnerEntityType(); ConditionValidCheckHelper.throwIfFalseWithCondition(() => false == owner_guid.isNullOrWhiteSpace(), () => $"Invalid OwnerGuid !!! : {owner_guid} - {owner.toBasicString()}, {parent.toBasicString()}"); (result, var sk) = makeAlertKey(trigger_type); if (result.isFail()) { return result; } ConditionValidCheckHelper.throwIfFalseWithCondition(() => false == sk.isNullOrWhiteSpace(), () => $"Invalid SK !!! : {sk} - {owner.toBasicString()}, {parent.toBasicString()}"); (result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(owner_guid, sk); if (result.isFail()) { return result; } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! : ownerGuid:{owner_guid}, sk:{sk} - {owner.toBasicString()}, {parent.toBasicString()}"); var query_config = dynamo_db_connector.makeQueryConfigForReadByPKSK(make_primary_key.PK, make_primary_key.SK); (result, var found_alert_record_doc) = await dynamo_db_connector.simpleQueryDocTypeWithQueryOperationConfig(query_config, false); if (result.isFail()) { continue; } if (null == found_alert_record_doc) { m_alert_toggles[trigger_type] = true; } else { m_alert_toggles[trigger_type] = false; } } return result; } public async Task onAlert(EntityAlertTriggerType alertTriggerType) { var owner = getOwner(); NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var err_msg = string.Empty; var result = new Result(); Player? master = null; if (parent is Player player) { master = player; } else if (parent is UgcNpc ugc_npc) { master = ugc_npc.onGetMasterEntity() as Player; } else { err_msg = $"Invalid EntityType !!! : EntityType:{parent.getEntityType()} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return; } NullReferenceCheckHelper.throwIfNull(master, () => $"master is null !!! - {owner.toBasicString()}, {parent.toBasicString()}"); var server_logic = GameServerApp.getServerLogic(); var dynamo_db_connector = server_logic.getDynamoDbClient(); if(false == m_alert_toggles.TryGetValue(alertTriggerType, out var found_alert_toggle)) { err_msg = $"Not found AlertToggle !!! : alertTriggerType:{alertTriggerType} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return; } if(false == found_alert_toggle) { err_msg = $"Check AlertToggle Off !!! : alertTriggerType:{alertTriggerType} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return; } if (false == m_alert_functions.TryGetValue(alertTriggerType, out var found_alert_function)) { err_msg = $"Not found AlertFunction !!! : alertTriggerType:{alertTriggerType} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().debug(err_msg); return; } (result, var doc_bases, var alert_method_type) = await found_alert_function.Invoke(alertTriggerType); if(result.isFail()) { err_msg = $"Failed to FnAlertFunction.Invoke !!! : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return; } var alert_record_attribute = owner.getEntityAttribute(); if (null == alert_record_attribute) { err_msg = $"Not found EntityAlertRecordAttribute !!!, alert_record_attribute is null - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return; } (result, DynamoDbDocBase? doc_base_4_alert) = await alert_record_attribute.toDocBase(); if (result.isFail()) { err_msg = $"Failed to toDocBase() !!!, in EntityAlertAction.onAlert() - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg); Log.getLogger().error(result.toBasicString()); return; } NullReferenceCheckHelper.throwIfNull(doc_base_4_alert, () => $"doc_base_4_alert is null !!! - {owner.toBasicString()}, {parent.toBasicString()}"); doc_bases.Add(doc_base_4_alert); var query_contexts = new List(); foreach (var doc in doc_bases) { (result, var query_context) = await doc.toDocumentQueryContext(); if (result.isFail()) { err_msg = $"Failed to toDocumentQueryContext() !!!, in EntityAlertAction.onAlert() : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return; } NullReferenceCheckHelper.throwIfNull(query_context, () => $"query_context is null !!! - {owner.toBasicString()}, {parent.toBasicString()}"); query_contexts.Add(query_context); } var alert_record_doc = doc_base_4_alert as EntityAlertRecordDoc; NullReferenceCheckHelper.throwIfNull(alert_record_doc, () => $"alert_record_doc is null !!! - {owner.toBasicString()}, {parent.toBasicString()}"); var table = dynamo_db_connector.getTableByDoc(alert_record_doc); (result, _) = await table.simpleTransactWriteWithDocument(query_contexts); if (result.isFail()) { err_msg = $"Failed to simpleTransactWriteWithDocument() !!!, in EntityAlertAction.onAlert() : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.DynamoDbTransactException, err_msg); Log.getLogger().error(err_msg); return; } m_alert_toggles[alertTriggerType] = false; if (EntityAlertMethodType.Mail == alert_method_type) { var found_user_mail_action = master.getEntityAction(); found_user_mail_action.NewReceivedMail(); } } private (Result, ALERT_KEY) makeAlertKey(EntityAlertTriggerType triggerType) { var owner = getOwner(); NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var err_msg = string.Empty; var result = new Result(); (result, var meta_id) = owner.onGetMetaIdOfEntityAlertTriggerType(triggerType); if(result.isFail()) { err_msg = $"Failed to getMetaIdOfEntityAlertType() !!! : {result.toBasicString()}, alertTriggerType:{triggerType} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return (result, string.Empty); } return (result, EntityAlertRecordDoc.makeALERT_KEY(triggerType, meta_id)); } public bool attachAlertFunction(EntityAlertTriggerType triggerType, FnAlertFunction fnAlertFunction) { var owner = getOwner(); NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var err_msg = string.Empty; if(false == m_alert_functions.TryAdd(triggerType, fnAlertFunction)) { err_msg = $"Already registered AlertFunction !!! : alertTriggerType:{triggerType} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return false; } m_alert_toggles[triggerType] = true; return true; } public bool detachAlertFunction(EntityAlertTriggerType triggerType) { var owner = getOwner(); NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var err_msg = string.Empty; if (false == m_alert_functions.TryRemove(triggerType, out _)) { err_msg = $"Failed to TryRemove() !!!, in detachAlertFunction() : alertTriggerType:{triggerType} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().warn(err_msg); return false; } m_alert_toggles[triggerType] = false; return true; } public bool hasAlert() { return 0 < m_alert_functions.Count; } }