Files
caliverse_server/ServerBase/Logic/ServerLogicBase.cs
2025-05-01 07:20:41 +09:00

1003 lines
34 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using Microsoft.Extensions.Configuration;
using NLog.Config;
using MySqlConnector;
using Nettention.Proud;
using StackExchange.Redis;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerControlCenter;
using MODULE_ID = System.UInt32;
namespace ServerBase;
public abstract partial class ServerLogicBase : IServerLogic
{
private ServerProgramVersion m_server_program_version = new();
private string m_server_type = string.Empty;
private string m_server_name = string.Empty;
private ServerConfig? m_server_config = null;
private IConfigurationRoot? m_configuration_root = null;
private ConfigManager? m_config_manager = null;
private ConcurrentDictionary<MODULE_ID, IModule> m_registered_mudules = new();
private List<IModule> m_initialized_modules = new();
private TaskCompletionSource<bool> m_run_tcs = new();
private readonly CancellationTokenSource m_cancel_token = new();
private PeriodicTaskTimer? m_server_info_notify_ticker;
private Task? m_server_info_notify_task_nullable;
private readonly ConcurrentDictionary<Type, RedisRequestSharedBase> m_redis_global_shared_caches = new();
private readonly ConcurrentDictionary<Type, IRule> m_rules = new();
// 전역적으로 관리해야 하는 엔티티들의 목록 !!!
private ConcurrentDictionary<Type, EntityBase> m_global_entities = new();
// 전역적으로 관리해야 하는 EntityTicker 목록 !!!
private ConcurrentDictionary<Type, EntityTicker> m_entity_tickers = new();
public string m_server_instanceid = string.Empty;
public ServerLogicBase(ServerConfig config)
{
m_server_config = config;
ServerLogicApp.setServerLogicApp(this);
}
public ServerLogicBase(ConfigManager configManager)
{
m_config_manager = configManager;
ServerLogicApp.setServerLogicApp(this);
}
public async Task<Result> tryCreateAndRegisterModule(Func<(IModule?, Result)> toCreateAction, bool initializeImmediately = false)
{
var err_msg = string.Empty;
var result = new Result();
(var module, result) = toCreateAction();
if(result.isFail())
{
err_msg = $"Failed to toCreateAction() !!!, in tryCreateAndAddModule() : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
NullReferenceCheckHelper.throwIfNull(module, () => $"module is null !!! - {toBasicString()}");
var module_id = module.getModuleContext().getModuleId();
result = await registerModule(module, initializeImmediately);
if (result.isFail())
{
err_msg = $"Failed to registerModule() !!!, in tryCreateAndAddModule() : {result.toBasicString()}, moduleId:{module_id} - {toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
public async Task<Result> registerModule(IModule moduleObject, bool initializeImmediately = false)
{
var err_msg = string.Empty;
var result = new Result();
var module_id = moduleObject.getModuleContext().getModuleId();
if (false == m_registered_mudules.TryAdd(module_id, moduleObject))
{
err_msg = $"Failed to TryAdd() !!!, in registerModule(), Already registred : moduleId:{module_id} - {toBasicString()}";
result.setFail(ServerErrorCode.ModuleAlreadyRegistred, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
if (true == m_initialized_modules.Exists(x => x.getModuleContext().getModuleId() == module_id))
{
err_msg = $"Already added initialzed Modules !!!, in registerModule() : moduleId:{module_id} - {toBasicString()}";
result.setFail(ServerErrorCode.ModuleAlreadyAddInitializeModule, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
m_initialized_modules.Add(moduleObject);
if (true == initializeImmediately)
{
var initializer = moduleObject as IInitializer;
NullReferenceCheckHelper.throwIfNull(initializer, () => $"initializer is null !!! - {toBasicString()}");
result = await initializer.onInit();
if (result.isFail())
{
err_msg = $"Failed to Initializer.onInit() !!!, in registerModule() : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
}
return result;
}
public void unregisterModule(MODULE_ID moduleId)
{
var err_msg = string.Empty;
var result = new Result();
if (m_registered_mudules.TryRemove(moduleId, out var removed_module))
{
err_msg = $"Failed to TryRemove() !!!, in unregisterModule() : moduleId:{moduleId} - {toBasicString()}";
Log.getLogger().warn(err_msg);
return;
}
NullReferenceCheckHelper.throwIfNull(removed_module, () => $"removed_module is null !!! - {toBasicString()}");
if (false == m_initialized_modules.Remove(removed_module))
{
err_msg = $"Failed to Remove() !!!, in unregisterModule() : moduleId:{moduleId} - {toBasicString()}";
Log.getLogger().error(err_msg);
}
}
public TModule getModule<TModule>(MODULE_ID targetModuleId)
where TModule : class, IModule
{
m_registered_mudules.TryGetValue(targetModuleId, out var found_module);
NullReferenceCheckHelper.throwIfNull(found_module, () => $"found_module is null !!!, Not registered Module : moduleId:{targetModuleId} - {toBasicString()}");
var casted_module = found_module as TModule;
NullReferenceCheckHelper.throwIfNull(casted_module, () => $"casted_module is null !!!, Failed to cast Module : TModule:{typeof(TModule)} - moduleId:{targetModuleId}, {toBasicString()}");
return casted_module;
}
//=============================================================================================
// for IServerLogic.getModule()
//=============================================================================================
public IModule getModule(MODULE_ID targetModuleId)
{
m_registered_mudules.TryGetValue(targetModuleId, out var found_module);
NullReferenceCheckHelper.throwIfNull(found_module, () => $"found_module is null !!!, Not registered Module : moduleId:{targetModuleId} - {toBasicString()}");
return found_module;
}
public async Task<Result> startModuleAll()
{
var result = new Result();
m_initialized_modules.OrderBy(x => { return x.getModuleContext().getSortStartOrderNo(); });
foreach (var module in m_initialized_modules)
{
result = await module.startModule();
if(result.isFail())
{
return result;
}
}
return result;
}
public async Task<Result> stopModuleAll()
{
var result = new Result();
m_initialized_modules.OrderBy(x => { return x.getModuleContext().getSortStopOrderNo(); });
foreach (var module in m_initialized_modules)
{
result = await module.stopModule();
if (result.isFail())
{
return result;
}
}
return result;
}
//=============================================================================================
// 서버 로직을 초기화 한다 !!!, onRunServer() 내에서 호출 된다 !!!
//=============================================================================================
public virtual async Task<Result> onInit()
{
var err_msg = string.Empty;
var result = new Result();
if (false == Log.isInitialized())
{
err_msg = $"The log is not initialized !!!, in ServiceLogicBase.onInit() !!! - {toBasicString()}";
result.setFail(ServerErrorCode.NlogNotInitialized, err_msg);
return result;
}
Log.getLogger().info($"Log.initLog() Start !!! : {toBasicString()}");
var with_configuration = this as IWithConfiguration;
if (null != with_configuration)
{
result = with_configuration.mergeConfiguration(getConfiguration());
if (result.isFail())
{
return result;
}
}
var config = getServerConfig();
result = await config.tryLoadConfig();
if (result.isFail())
{
return result;
}
DotNetDumpHelper.init(config.DumpDir, onGetDumpFilename());
result = onCreateServerName();
if (result.isFail())
{
err_msg = $"Failed to onCreateServerName() !!! : {result.toBasicString()}";
Log.getLogger().fatal(err_msg);
return result;
}
result = await onConfigureCloudEnvironment();
if (result.isFail())
{
err_msg = $"Failed to onConfigureCloudEnvironment() !!! : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().fatal(err_msg);
return result;
}
LogicThread.start(config.SingleThreaded);
ServerConfigHelper.init(config);
result = onLoadMetaDatas();
if (result.isFail())
{
err_msg = $"Failed to onLoadMetaDatas() !!! : {result.toBasicString()}";
Log.getLogger().fatal(err_msg);
return result;
}
result = await onRegisterModuleAll();
if (result.isFail())
{
err_msg = $"Failed to onRegisterModuleAll() !!! : {result.toBasicString()}";
Log.getLogger().fatal(err_msg);
return result;
}
var to_initializers = new Initializers();
foreach (var module in m_initialized_modules)
{
var initializer = module as IInitializer;
if(null == initializer) { continue; }
to_initializers.appendInitializer(initializer);
}
result = await to_initializers.init("Initialize Module All");
if (result.isFail())
{
Log.getLogger().error($"Failed to Initializers.init() !!! : {result.toBasicString()} - {toBasicString()}");
return result;
}
result = await onInitGlobalEntities();
if (result.isFail())
{
Log.getLogger().error($"Failed to onInitGlobalEntities() !!! : {result.toBasicString()} - {toBasicString()}");
return result;
}
result = await onInitRules();
if (result.isFail())
{
Log.getLogger().error($"Failed to onInitRules() !!! : {result.toBasicString()} - {toBasicString()}");
return result;
}
result = onInitFirewall();
if (result.isFail())
{
err_msg = $"Failed to onInitFirewall() !!! : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().fatal(err_msg);
return result;
}
if (false == onLoadProgramVersionInfo())
{
err_msg = $"Failed to onLoadProgramVersionInfo() !!! - {toBasicString()}";
result.setFail(ServerErrorCode.ProgramVersionLoadFailed, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
Log.getLogger().info($"Success ServiceLogicBase.onInit() - {toBasicString()}");
return result;
}
protected abstract Result onLoadMetaDatas();
public virtual async Task<Result> onCreateServerInfoSyncTask()
{
var result = new Result();
m_server_info_notify_ticker = new PeriodicTaskTimer( GetType().Name
, ServerBase.Constant.SERVER_INFO_NOTIFY_INTERVAL_MSEC
, m_cancel_token, onTaskServerInfoSyncTick);
m_server_info_notify_task_nullable = m_server_info_notify_ticker.getTask();
Log.getLogger().info($"Success ServerLogicBase.onCreateTask() - {toBasicString()}");
return await Task.FromResult(result);
}
public virtual async Task onTaskServerInfoSyncTick()
{
await Task.CompletedTask;
}
protected virtual List<RedisRequestSharedBase> onAppendRedisGlobalSharedCacheAll()
{
return new List<RedisRequestSharedBase>();
}
public RedisRequestSharedBase? findRedisGlobalSharedRequest<TRedisGlobalSharedRequest>()
where TRedisGlobalSharedRequest : RedisRequestSharedBase
{
m_redis_global_shared_caches.TryGetValue(typeof(TRedisGlobalSharedRequest), out var found_redis_global_shard_request);
return found_redis_global_shard_request;
}
protected virtual async Task<Result> onInitGlobalEntities()
{
var result = new Result();
var err_msg = string.Empty;
var to_append_global_entities = onAppendGlobalEntityAll();
foreach (var entity in to_append_global_entities)
{
if (false == m_global_entities.TryAdd(entity.GetType(), entity))
{
err_msg = $"Failed to TryAdd() !!!, duplcated EntityBase : duplicatedEntityBase:{entity.getTypeName()} - {toBasicString()}";
result.setFail(ServerErrorCode.RedisGlobalEntityDuplicated, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
}
var to_init_global_entities = new Initializers();
foreach (var each in m_global_entities)
{
to_init_global_entities.appendInitializer(each.Value);
}
result = await to_init_global_entities.init("GlobalEntities");
if (result.isFail())
{
err_msg = $"Failed to init() GlobalEntities !!! : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().fatal(err_msg);
return result;
}
Log.getLogger().info($"Success ServerLogicBase.onInitGlobalEntities() - {toBasicString()}");
return result;
}
protected virtual List<EntityBase> onAppendGlobalEntityAll()
{
// 전역적으로 관리할 EntityBase를 상속 받은 클래스를 정의하여 List<EntityBase> 에 추가 한다.
// EntityBase.onInit() 호출이 될때 전역적 객체의 역할에 필요로 하는 기반 정보를 모두 준비할 수 있어야 한다.
// 그 결과가 실패시 서버는 종료되어야 한다 !!!
// 본 구조를 클래스 설계시 궁금한 부분이 있으면 슬랙을 통해 문의 바랍니다. !!! - kangms
return new List<EntityBase>();
}
public TEntity? findGlobalEntity<TEntity>()
where TEntity : EntityBase
{
m_global_entities.TryGetValue(typeof(TEntity), out var found_global_entity);
return found_global_entity as TEntity;
}
public bool addGlobalEntity<TEntity>(TEntity toAddEntityBase)
where TEntity : EntityBase
{
return m_global_entities.TryAdd(toAddEntityBase.GetType(), toAddEntityBase);
}
protected virtual void onInitBusinessLog()
{
BusinessLogger.setup( new NLogAppender()
, new JsonText()
, LogTransToOutputType.TransToMultyLine );
Log.getLogger().info($"Success ServerLogicBase.onInitBusinessLog() - {toBasicString()}");
}
protected virtual Result onCreateServerName()
{
var result = new Result();
var err_msg = string.Empty;
var server_type_name = getServerType();
var server_type = server_type_name.toServerType();
if (false == server_type.isValidServerType())
{
err_msg = $"ServerType invalid !!! : {server_type.ToString()}";
result.setFail(ServerErrorCode.ServerTypeInvalid, err_msg);
return result;
}
var server_config = getServerConfig();
var listen_port = server_config.toClientListenPort();
if (listen_port <= 0)
{
err_msg = $"Client listen port invalid !!! : appParamPort:{listen_port}, configListenPort:{server_config.ClientListenPort} - {server_type.ToString()}";
result.setFail(ServerErrorCode.ClientListenPortInvalid, err_msg);
return result;
}
setServerName(server_type.toServerName(server_config.toClientListenIP(), listen_port));
return result;
}
protected virtual async Task<Result> onConfigureCloudEnvironment()
{
var result = new Result();
var config = getServerConfig();
if (config.AWS.CloudWatchLog.Enable)
{
result = setupCloudwatchLog(config);
if (result.isFail())
{
return result;
}
}
if (config.AWS.Enable)
{
m_server_instanceid = await AwsHelper.getAwsInstanceId();
}
return result;
}
private Result setupCloudwatchLog(ServerConfig serverConfig)
{
var result = new Result();
var err_msg = string.Empty;
if (false == CloudWatchLog.isOpened())
{
return result;
}
if (false == CloudWatchLog.setup( serverConfig.AWS.CloudWatchLog.CloudWatchLogGroup
, serverConfig.AWS.CloudWatchLog.CloudWatchLogNamePattern
, serverConfig.AWS.CloudWatchLog.CloudWatchLogLevel
, serverConfig.AWS.Region
, serverConfig.AWS.AccessKey
, serverConfig.AWS.SecretKey
, serverConfig.AWS.CloudWatchLog.CloudWatchLogLayout))
{
err_msg = $"Failed to CloudWatchLog.setup() !!! - {toBasicString()}";
result.setFail(ServerErrorCode.NlogWithAwsCloudWatchSetupFailed, err_msg);
Log.getLogger().fatal(result.toBasicString());
return result;
}
return result;
}
private void onNLogConfigurationChanged(object? sender, LoggingConfigurationChangedEventArgs e)
{
var result = new Result();
var err_msg = string.Empty;
var server_config = getServerConfig();
if (null == server_config)
{
// Log.shutdown() 호출시 타이밍에 따라 server_config가 null인 경우가 있다 !!! - kangms
return;
}
if (server_config.AWS.CloudWatchLog.Enable)
{
result = setupCloudwatchLog(server_config);
if (result.isFail())
{
err_msg = $"Failed to setupCloudwatchLog() !!! in onNLogConfigurationChanged() : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().fatal(err_msg);
}
}
}
protected virtual async Task<Result> onRegisterModuleAll()
{
return await Task.FromResult(new Result());
}
protected virtual List<IRule> onAppendRuleAll()
{
return new List<IRule>();
}
protected virtual async Task<Result> onInitRules()
{
var result = new Result();
var err_msg = string.Empty;
var to_append_rules = onAppendRuleAll();
foreach(var rule in to_append_rules)
{
if (false == m_rules.TryAdd(rule.GetType(), rule))
{
err_msg = $"Failed to TryAdd() !!!, duplcated RuleType : duplicatedRuleType:{rule.getTypeName()} - {toBasicString()}";
result.setFail(ServerErrorCode.RuleTypeDuplicated, err_msg);
Log.getLogger().error(err_msg);
return result;
}
}
var to_init_ruels = new Initializers();
foreach(var each in m_rules)
{
to_init_ruels.appendInitializer(each.Value);
}
return await to_init_ruels.init("Rules");
}
public TRule? findRule<TRule>()
where TRule : class
{
if(false == m_rules.TryGetValue(typeof(TRule), out var rule))
{
return null;
}
return rule as TRule;
}
protected virtual Result onInitFirewall()
{
var result = new Result();
var err_msg = string.Empty;
var server_config = getServerConfig();
// 사용자 로그인 차단 여부를 설정 한다. (활성화:true/비활성화:false), 관제 시스템을 통해 변경 가능 하다 !!! - kangms
m_account_login_block_enable.set(server_config.AccountLoginBlockEnable);
return result;
}
protected virtual bool onLoadProgramVersionInfo()
{
var config = getServerConfig();
var version_paths = config.getVersionPaths();
if(version_paths == null)
{
var err_msg = $"Failed to getProgramVersion() !!!, not found ProgramVersion !!! - {toBasicString()}";
Log.getLogger().error(err_msg);
return false;
}
var result = new Result();
foreach(var each in version_paths)
{
var version_type = each.Key;
var version_file_path = each.Value;
(result, var build_version, var revision) = VersionHelper.tryReadVersion(version_file_path);
if(result.isFail())
{
var err_msg = $"Failed to tryReadVersion() !!! : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
return false;
}
result = m_server_program_version.appendVersion(version_type, build_version, revision);
if(result.isFail())
{
var err_msg = $"Failed to appendVersion() !!! : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
return false;
}
}
return true;
}
private void setThreadPool()
{
var config = getServerConfig();
System.Threading.ThreadPool.GetMinThreads(out var minWorker, out var minIOCP);
Log.getLogger().info($"Application configured Thread : minWorkerThreadCount:{minWorker}, minIOCPThreadCount:{minIOCP} - {toBasicString()}");
var min_worker = config.MinWorkerThreadCount <= 0 ? minWorker : config.MinWorkerThreadCount;
var min_ioc = config.MinIOCThreadCount <= 0 ? minIOCP : config.MinIOCThreadCount;
if (false == System.Threading.ThreadPool.SetMinThreads(min_worker, min_ioc))
{
Log.getLogger().error($"Failed to SetMinThreads() : minWorkerThreadCount:{min_worker}, minIOCPThreadCount:{min_ioc} - {toBasicString()}");
return;
}
Log.getLogger().info($"Success Change Thread Count : minWorkerThreadCount:{min_worker}, minIOCPThreadCount:{min_ioc} - {toBasicString()}");
}
//=============================================================================================
// 서버 로직을 시작 한다. !!!
//=============================================================================================
public virtual async Task<Result> onRunServer()
{
var result = new Result();
var err_msg = string.Empty;
setServerStopEvent();
Log.initLog(getServerName(), "Developer", onNLogConfigurationChanged);
onInitBusinessLog();
result = await onInit();
if (result.isFail())
{
Log.getLogger().error($"Failed to ServerLogicBase.onInit() !!!, in onRunServer() : {result.toBasicString()} - {toBasicString()}");
return result;
}
setThreadPool();
result = await startModuleAll();
if (result.isFail())
{
return result;
}
var server_Metrics = this as IWithServerMetrics;
if (null != server_Metrics)
{
result = await server_Metrics.setupServerMetrics();
if (result.isFail())
{
return result;
}
}
result = await onCreateTickerAll();
if (result.isFail())
{
Log.getLogger().error($"Failed to ServerLogicBase.onCreateTickerAll() !!!, in onRunServer() : {result.toBasicString()} - {toBasicString()}");
return result;
}
result = await onStartServer();
if(result.isFail())
{
Log.getLogger().error($"Failed to ServerLogicBase.onStartServer() !!!, in onRunServer() : {result.toBasicString()} - {toBasicString()}");
return result;
}
var running_task = onRunning();
if (running_task == null)
{
err_msg = $"Failed to ServiceLogicBase.onRunning() !!! - {toBasicString()}";
result.setFail(ServerErrorCode.ServerOnRunningFailed, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
await running_task;
return result;
}
protected virtual Task? onRunning()
{
return m_run_tcs?.Task;
}
private void setServerStopEvent()
{
//=====================================================================================
// SIGINT 콘솔 시그널 발생시 (프로세스 종료) : 서버 종료 처리 등록
//=====================================================================================
Console.CancelKeyPress += async (s, e) =>
{
await stopServerByExitEvent();
};
//=====================================================================================
// Process 종료시 : 서버 종료 처리 등록
//=====================================================================================
AppDomain.CurrentDomain.ProcessExit += async (s, e) =>
{
await stopServerByExitEvent();
};
}
protected virtual async Task<Result> onStartServer()
{
var err_msg = string.Empty;
var result = new Result();
var server_Metrics = this as IWithServerMetrics;
if(null != server_Metrics)
{
await onCreateServerInfoSyncTask();
}
Log.getLogger().info($"Running Server : {getServerName()} - {toBasicString()}");
await NamedPipeMonitor.ChangeServerStatus(ServerStatus.Running);
return result;
}
public virtual async Task onStopServer()
{
Log.getLogger().info("Call onStopServer() !!!");
var server_Metrics = this as IWithServerMetrics;
if (null != server_Metrics)
{
if(true == server_Metrics.isSetupCompleted())
{
var server_metrics_request = server_Metrics.getServerMetricsCacheRequest();
NullReferenceCheckHelper.throwIfNull(server_metrics_request, () => $"server_metrics_request is null - {toBasicString()}");
var handler_type = (uint)ServerMetricsCacheRequest.TriggerType.ServerMetrics_RemoveByServerName;
await server_metrics_request.tryRunTriggerHandler(handler_type, getServerName());
}
}
await NamedPipeMonitor.StopNamedPipeService();
await stopModuleAll();
m_cancel_token.Cancel();
Log.getLogger().info("onStopServer() - stopEntityTickerAll() !!!");
await stopEntityTickerAll();
if (null != m_server_info_notify_task_nullable)
{
m_server_info_notify_task_nullable.Wait();
}
Log.getLogger().info("onStopServer() - m_server_info_notify_task_nullable.Wait() !!!");
m_run_tcs?.SetResult(true);
Log.getLogger().info("onStopServer finish !!!");
}
private async Task stopServerByExitEvent()
{
await onStopServer();
LogicThread.join();
}
public virtual async Task<Result> onInitServerKeyToCache(int worldId)
{
var result = new Result();
var err_msg = string.Empty;
var server_name = getServerName();
var server_type = getServerType().toServerType();
var server_Metrics = this as IWithServerMetrics;
if (null != server_Metrics)
{
var server_metrics_request = server_Metrics.getServerMetricsCacheRequest();
NullReferenceCheckHelper.throwIfNull(server_metrics_request, () => $"server_metrics_request is null - {toBasicString()}");
var handler_type = (uint)ServerMetricsCacheRequest.TriggerType.ServerMetrics_Init;
var with_result_value = await server_metrics_request.tryRunTriggerHandler(handler_type, server_name, server_type, worldId);
if (with_result_value.Result.isFail())
{
err_msg = $"Failed to tryRunTriggerHandler() !!! : handlerType:{handler_type}, {with_result_value.Result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
return with_result_value.Result;
}
}
return result;
}
public virtual async Task<Result> onCreateTickerAll()
{
await Task.CompletedTask;
Log.getLogger().warn($"No Ticker object has been created !!!, in onCreateTickerAll() - {toBasicString()}");
return new Result();
}
public Result registerEntityTicker(EntityTicker entityTicker)
{
var result = new Result();
var err_msg = string.Empty;
if (false == m_entity_tickers.TryAdd(entityTicker.GetType(), entityTicker))
{
err_msg = $"Already registered EntityTicker !!!";
result.setFail(ServerErrorCode.EntityTickerAlreadyRegistered, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public Result unregisterEntityTicker(EntityTicker entityTicker)
{
var result = new Result();
var err_msg = string.Empty;
if (false == m_entity_tickers.TryRemove(entityTicker.GetType(), out var removed_entity_ticker))
{
err_msg = $"Not found EntityTicker !!! : {entityTicker.toBasicString()}";
result.setFail(ServerErrorCode.EntityTickerNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public TEntityTicker? findEntityTicker<TEntityTicker>()
where TEntityTicker : EntityTicker
{
var result = new Result();
var err_msg = string.Empty;
var type = typeof(TEntityTicker);
if (false == m_entity_tickers.TryGetValue(type, out var found_entity_ticker))
{
err_msg = $"Not found EntityTicker !!! : {type.Name}";
result.setFail(ServerErrorCode.EntityTickerNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return null;
}
return found_entity_ticker as TEntityTicker;
}
protected Task stopEntityTickerAll()
{
var waiting_tasks = new List<Task>();
foreach(var each in m_entity_tickers)
{
var timer = each.Value.getPeriodicTaskTimer();
if(null == timer)
{
continue;
}
timer.cancelTimer();
waiting_tasks.Add(timer.getTask());
}
Log.getLogger().info("onStopServer - stopEntityTickerAll() - start !!!");
Task.WaitAll(waiting_tasks.ToArray());
Log.getLogger().info("onStopServer - stopEntityTickerAll() - end !!!");
return Task.CompletedTask;
}
public bool onSendPacket<T>(IEntityWithSession session, T msg)
where T : class, IMessage
{
var listen_session_base = this.getListenSessionBase();
NullReferenceCheckHelper.throwIfNull(listen_session_base, () => $"listen_session_base is null !!! - {toBasicString()}");
return listen_session_base.onSendPacket<T>(session, msg);
}
public bool onSendPacket<T>(IEntityWithSession[] sessions, T msg)
where T : class, IMessage
{
var listen_session_base = this.getListenSessionBase();
NullReferenceCheckHelper.throwIfNull(listen_session_base, () => $"listen_session_base is null !!! - {toBasicString()}");
return listen_session_base.onSendPacket<T>(sessions, msg);
}
public async Task<Result> onCallProtocolHandler<T>(IEntityWithSession session, T recvProtocol)
where T : Google.Protobuf.IMessage
{
var listen_session_base = session.getListenSessionBase();
NullReferenceCheckHelper.throwIfNull(listen_session_base, () => $"listen_session_base is null !!! - {toBasicString()}");
return await listen_session_base.onCallProtocolHandler(session, recvProtocol);
}
protected virtual string onGetDumpFilename()
{
NullReferenceCheckHelper.throwIfNull(m_server_config, () => $"m_server_config is null !!!");
return getServerName() + "_" + m_server_config.getAppParamPort();
}
public string toBasicString()
{
return $"ServerType:{getServerType()}, ServerName:{getServerName()}";
}
protected virtual async Task<bool> onSetAccountLoginBlock(bool isBlock)
{
await Task.CompletedTask;
var block_enable = getAccountLoginBlockEnable();
return false != block_enable.set(isBlock);
}
public virtual async Task<bool> onBlockAccountLogin()
{
var is_success = await onSetAccountLoginBlock(true);
if (false == is_success)
{
Log.getLogger().error($"Failed to block account login !!! : currBlockState:{getAccountLoginBlockEnable().Value}");
}
return is_success;
}
public virtual async Task<bool> onCancelAccountLoginBlock()
{
var is_success = await onSetAccountLoginBlock(false);
if (false == is_success)
{
Log.getLogger().error($"Failed to cancel Block account login !!! : currBlockState:{getAccountLoginBlockEnable().Value}");
}
return is_success;
}
private AtomicBool m_account_login_block_enable = new(false);
}