using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections.Concurrent; using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DocumentModel; using Amazon.DynamoDBv2.Model; using Amazon.Runtime; using ServerCore; using ServerBase; using DYNAMO_DB_TABLE_NAME = System.String; using DYNAMO_DB_TABLE_FULL_NAME = System.String; namespace ServerBase; public partial class DynamoDbClient : DynamoDbConnectorBase, IModule, IInitializer { public const string TTL_NAME = "TTL"; public const string SK_EMPTY = "empty"; public const string PK_GLOBAL = "global"; private readonly ModuleContext? m_module_context; public DynamoDbClient() : base() { } public DynamoDbClient(ModuleContext moduleContext) : base() { m_module_context = moduleContext; } public async Task onInit() { var err_msg = string.Empty; var result = new Result(); var module_context = getModuleContext(); var config_param = module_context.getConfigParam() as ConfigParam; NullReferenceCheckHelper.throwIfNull(config_param, () => $"config_param is null !!!"); result = connectToDb(config_param); if (result.isFail()) { err_msg = $"Failed to create DB Table !!! - {toBasicString()}"; Log.getLogger().fatal(result.toBasicString()); return result; } if (false == await createDBIfNotExists(false)) { err_msg = $"Failed to createDBIfNotExists() !!! - {toBasicString()}"; result.setFail(ServerErrorCode.DynamoDbTableCreateFailed, err_msg); Log.getLogger().fatal(result.toBasicString()); return result; } return result; } public async Task startModule() { var result = new Result(); return await Task.FromResult(result); } public async Task stopModule() { var result = new Result(); return await Task.FromResult(result); } public Result connectToDb(ConfigParam configParam) { var result = new Result(); var err_msg = string.Empty; (var error_code, var to_load_table_names) = ServerConfigHelper.getDynamoDbTableNamesWithServiceType(configParam.ServiceType); if (error_code.isFail()) { err_msg = $"Failed to DynamoDbClient.getDynamoDbTableNameWithServiceType() !!! : {configParam.toBasicString()} - {toBasicString()}"; result.setFail(error_code, err_msg); Log.getLogger().error(err_msg); return result; } return connectToDb( to_load_table_names , configParam.IsLocalDynamoDB, configParam.UrlOfDynamoDb , configParam.AccessKeyOfAws, configParam.SecretKeyOfAws, configParam.RegionOfAws ); } public Result connectToDb( ConcurrentDictionary tableNames, bool localDynamoDb , string dynamodbUrl , string awsAccessKey, string awsSecretKey , string awsRegion = "" ) { var result = new Result(); var err_msg = string.Empty; foreach( var each in tableNames ) { var table_name = each.Key; var table_full_name = each.Value; if(false == addTableFullName(table_name, table_full_name)) { err_msg = $"Failed to addTableFullName() !!! : tableName:{table_name}, tableFullName:{table_full_name} - {toBasicString()}"; result.setFail(ServerErrorCode.DynamoDbTableNameDuplicated, err_msg); Log.getLogger().fatal(result.toBasicString()); return result; } } var db_config = new AmazonDynamoDBConfig(); db_config.BufferSize = 4 * 1024 * 1024; // 4 MB db_config.RetryMode = RequestRetryMode.Standard; db_config.DisableLogging = false; // Logging is disabled by default. - Set to true to enable request-level logging. db_config.ThrottleRetries = false; // Throttled requests are not automatically retried. - Set to false to automatically retry throttled requests. if (localDynamoDb) { // DynamoDB-Local is running, so create a client Log.getLogger().info($"Setting up a DynamoDB-Local client (DynamoDB Local seems to be running)"); db_config.ServiceURL = dynamodbUrl; if (false == base.connectToDb(awsAccessKey, awsSecretKey, db_config)) { err_msg = $"Failed to connect a DynamoDB-Local client !!! : {toBasicString()}"; result.setFail(ServerErrorCode.DynamoDbConnectFailed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } } else { Log.getLogger().info($"Setting up a DynamoDB-Remote client : TargetRegion:{awsRegion}"); try { db_config.RegionEndpoint = Amazon.RegionEndpoint.GetBySystemName(awsRegion); if (false == base.connectToDb(awsAccessKey, awsSecretKey, db_config)) { err_msg = $"Failed to connect a DynamoDB-Remote client !!! : {toBasicString()}"; result.setFail(ServerErrorCode.DynamoDbConnectFailed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } } catch (Exception e) { err_msg = $"Failed to connect a DynamoDB-Remote client !!! : Exception:{e}, {toBasicString()}"; result.setFail(ServerErrorCode.DynamoDbConnectFailed, err_msg); Log.getLogger().fatal(result.toBasicString()); return result; } } return result; } public Result connectToDb( string tableName, bool localDynamoDB, string dynamodbUrl , string awsAccessKey, string awsSecretKey, string awsRegion = "") { var table_names = new ConcurrentDictionary(); table_names[tableName] = tableName; return connectToDb( table_names, localDynamoDB, dynamodbUrl , awsAccessKey, awsSecretKey, awsRegion ); } public async Task createDBIfNotExists(bool resetTable) { var err_msg = string.Empty; var db_client = getDbClient(); if (db_client == null) { err_msg = $"Not created DynamoDbClient !!! - {toBasicString()}"; Log.getLogger().fatal(err_msg); return false; } var loaded_table_full_names = getTableNames().Values.ToList(); if (resetTable == true) { if(false == await deleteTables(loaded_table_full_names)) { err_msg = $"Failed to DynamoDbClient.deleteTables() !!! - {toBasicString()}"; Log.getLogger().fatal(err_msg); return false; } } List tableAttributes = new List(); tableAttributes.Add(new AttributeDefinition(PrimaryKey.PK_Define, ScalarAttributeType.S)); tableAttributes.Add(new AttributeDefinition(PrimaryKey.SK_Define, ScalarAttributeType.S)); List tableKeySchema = new List(); tableKeySchema.Add(new KeySchemaElement(PrimaryKey.PK_Define, KeyType.HASH)); tableKeySchema.Add(new KeySchemaElement(PrimaryKey.SK_Define, KeyType.RANGE)); foreach (var table_full_name in loaded_table_full_names) { if (await isExistTable(table_full_name) == false) { var ttl_update = new UpdateTimeToLiveRequest { TableName = table_full_name, TimeToLiveSpecification = new TimeToLiveSpecification { AttributeName = TTL_NAME, // TTL로 사용할 속성 이름 Enabled = true // TTL 사용 여부 } }; if(false == await createTable( db_client, table_full_name, ttl_update , tableAttributes, tableKeySchema )) { err_msg = $"Failed to DynamoDbClient.addTable() !!! - {toBasicString()}"; Log.getLogger().fatal(err_msg); return false; } } if(false == addTable(table_full_name, Table.LoadTable(db_client, table_full_name))) { err_msg = $"Failed to DynamoDbClient.addTable() !!! : tableName:{table_full_name} - {toBasicString()}"; Log.getLogger().fatal(err_msg); return false; } } DynamoDbQueryOperationOptionConfig.configure(); return true; } public Table getTableByDoc() where TDoc : DynamoDbDocBase, new() { return getTableByName((new TDoc()).TableName); } public Table getTableByDoc(TDoc doc) where TDoc : DynamoDbDocBase { return getTableByName(doc.TableName); } public ModuleContext getModuleContext() { NullReferenceCheckHelper.throwIfNull(m_module_context, () => $"m_module_context is null !!!"); return m_module_context; } }