Files
caliverse_server/ServerCore/DynamoDB/DynamoDbConnectorBase.cs
2025-11-28 16:54:56 +09:00

265 lines
9.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using Newtonsoft.Json;
using Amazon.Runtime;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using Axion.Collections.Concurrent;
using DYNAMO_DB_TABLE_NAME = System.String;
using DYNAMO_DB_TABLE_FULL_NAME = System.String;
using MongoDB.Driver.Core.Configuration;
namespace ServerCore;
// HANDOVER: AmazonDynamoDBClient SDK Wrapper 클래스 이다.
// Table 생성시 없으면 자동 생성 기능을 제공 한다.
public abstract class DynamoDbConnectorBase
{
// 하나의 아이템 최대 저장 크기 : PK + SK + ITEM <= ITEM_MAX_SIZE_BYTES
public static readonly UInt32 ITEM_MAX_SIZE_BYTES = 400 * 1024;
private AmazonDynamoDBClient? m_db_client;
private ConcurrentDictionary<DYNAMO_DB_TABLE_NAME, DYNAMO_DB_TABLE_FULL_NAME> m_to_load_table_names = new();
private string m_access_key = string.Empty;
private string m_secret_key = string.Empty;
private AmazonDynamoDBConfig? m_db_config;
private ConcurrentDictionary<DYNAMO_DB_TABLE_FULL_NAME, Table> m_loaded_tables = new();
public bool connectToDb(string accessKey, string secretKey, AmazonDynamoDBConfig dbConfig)
{
m_access_key = accessKey;
m_secret_key = secretKey;
m_db_config = dbConfig;
try
{
m_db_client = new AmazonDynamoDBClient(accessKey, secretKey, dbConfig);
}
catch (Exception e)
{
Log.getLogger().error($"Exception !!!, Failed to perform in DynamoDbConnectorBase.connectToDb() !!! : exception:{e}, AccessKey:{accessKey}, SecretKey:{secretKey} - {toBasicString()}");
return false;
}
return true;
}
public async Task<bool> isExistTable(string tableName)
{
try
{
if (m_db_client == null)
{
return false;
}
var loaded_tables = await m_db_client.ListTablesAsync();
return loaded_tables.TableNames.Contains(tableName);
}
catch (Exception e)
{
Log.getLogger().fatal($"Exception !!!, Failed to perform in DynamoDbConnectorBase.isExistTable() !!! : exception:{e}, toFindTableName{tableName}");
return false;
}
}
public static async Task<bool> createTable( AmazonDynamoDBClient dbClient, DYNAMO_DB_TABLE_FULL_NAME tableFullName
, UpdateTimeToLiveRequest ttlUpdate
, List<AttributeDefinition> tableAttributes
, List<KeySchemaElement> tableKeySchema )
{
var request = new CreateTableRequest
{
TableName = tableFullName,
AttributeDefinitions = tableAttributes,
KeySchema = tableKeySchema,
BillingMode = BillingMode.PAY_PER_REQUEST
};
try
{
var new_table = await dbClient.CreateTableAsync(request);
Log.getLogger().info($"Created DynamoDB Table : {new_table.TableDescription.TableName}");
var ttl_res = await dbClient.UpdateTimeToLiveAsync(ttlUpdate);
if (System.Net.HttpStatusCode.OK != ttl_res.HttpStatusCode)
{
Log.getLogger().fatal($"Failed to UpdateTimeToLiveAsync() !!!, not configured TTL : {ttlUpdate.TimeToLiveSpecification.AttributeName}, toCreateTableName{tableFullName}");
return false;
}
var ttl_status_res = await dbClient.DescribeTimeToLiveAsync(new DescribeTimeToLiveRequest { TableName = tableFullName });
if (TimeToLiveStatus.ENABLED != ttl_status_res.TimeToLiveDescription.TimeToLiveStatus)
{
Log.getLogger().fatal($"Failed to check configured TTL !!! : ttlName:{ttlUpdate.TimeToLiveSpecification.AttributeName}, toCreateTableName{tableFullName}");
return false;
}
}
catch (Exception e)
{
Log.getLogger().fatal($"Exception !!!, Failed to perform in DynamoDbConnectorBase.createTable() !!! : exception:{e}, toCreateTableName{tableFullName}");
return false;
}
return true;
}
public static bool checkItemSizeLimit(string itemString)
{
var bytes = Encoding.UTF8.GetBytes(itemString);
if (bytes.Length > ITEM_MAX_SIZE_BYTES)
{
return false;
}
return true;
}
public async Task<bool> createTable( DYNAMO_DB_TABLE_FULL_NAME tableFullName
, List<AttributeDefinition> tableAttributes
, List<KeySchemaElement> tableKeySchema
, List<GlobalSecondaryIndex> globalSecondaryIndexes)
{
var request = new CreateTableRequest
{
TableName = tableFullName,
AttributeDefinitions = tableAttributes,
KeySchema = tableKeySchema,
GlobalSecondaryIndexes = globalSecondaryIndexes,
BillingMode = BillingMode.PAY_PER_REQUEST
};
try
{
if (m_db_client == null)
{
return false;
}
var new_table = await m_db_client.CreateTableAsync(request);
Log.getLogger().info($"Created DynamoDB Table : {new_table.TableDescription.TableName}");
}
catch (Exception e)
{
Log.getLogger().fatal($"Exception !!!, Failed to perform in DynamoDbConnectorBase.createTable() !!! : exception:{e}, toCreateTableName{tableFullName}");
return false;
}
return true;
}
public async Task<bool> deleteTables(List<DYNAMO_DB_TABLE_FULL_NAME> tableFullNames)
{
foreach(var table_full_name in tableFullNames)
{
var request = new DeleteTableRequest
{
TableName = table_full_name,
};
try
{
if (m_db_client == null)
{
return false;
}
var deleted_table = await m_db_client.DeleteTableAsync(request);
}
catch (Exception e)
{
Log.getLogger().fatal($"Exception !!!, Failed to perform in DynamoDbConnectorBase.deleteTables() !!! : exception:{e}, toDeleteTableName{table_full_name}");
return false;
}
}
return true;
}
public async Task<TableDescription?> getTableDescription(DYNAMO_DB_TABLE_FULL_NAME tableFullName)
{
try
{
if (m_db_client == null)
{
return null;
}
var response = await m_db_client.DescribeTableAsync(tableFullName);
return response.Table;
}
catch (Exception e)
{
Log.getLogger().fatal($"Exception !!!, Failed to perform in DynamoDbConnectorBase.getTableDescription() !!! : exception:{e}, TableName{tableFullName}");
return null;
}
}
public Table getTableByName(DYNAMO_DB_TABLE_NAME tableName)
{
m_to_load_table_names.TryGetValue(tableName, out var table_full_name);
NullReferenceCheckHelper.throwIfNull(table_full_name, () => $"table_full_name is null !!! : tableName:{tableName}");
m_loaded_tables.TryGetValue(table_full_name, out var table);
NullReferenceCheckHelper.throwIfNull(table, () => $"table is null !!!, Not found DynamoDb Table !!! : tableFullName:{table_full_name}");
return table;
}
public Table getTableByFullName(DYNAMO_DB_TABLE_FULL_NAME tableFullName)
{
m_loaded_tables.TryGetValue(tableFullName, out var table);
NullReferenceCheckHelper.throwIfNull(table, () => $"table is null !!!, Not found DynamoDb Table !!! : tableFullName:{tableFullName}");
return table;
}
public bool addTable(DYNAMO_DB_TABLE_FULL_NAME tableFullName, Table loadedTable)
{
return m_loaded_tables.TryAdd(tableFullName, loadedTable);
}
public bool hasTableName(DYNAMO_DB_TABLE_NAME tableName) => m_to_load_table_names.ContainsKey(tableName);
public DYNAMO_DB_TABLE_FULL_NAME getTableFullName(DYNAMO_DB_TABLE_NAME tableName)
{
m_to_load_table_names.TryGetValue(tableName, out var table_full_name);
NullReferenceCheckHelper.throwIfNull(table_full_name, () => $"table_full_name is null !!! : tableName:{tableName}");
return table_full_name;
}
public ConcurrentDictionary<DYNAMO_DB_TABLE_NAME, DYNAMO_DB_TABLE_FULL_NAME> getTableNames() => m_to_load_table_names;
protected bool addTableFullName(DYNAMO_DB_TABLE_NAME tableName, DYNAMO_DB_TABLE_FULL_NAME tableFullName) => m_to_load_table_names.TryAdd(tableName, tableFullName);
public string toConnectionKeyString()
{
return $"AccessKey:{m_access_key}, SecretKey:{m_secret_key}";
}
public string toBasicString()
{
return $"ServerUrl:{m_db_config?.ServiceURL}, RegionEndPoint:{m_db_config?.RegionEndpoint}";
}
public AmazonDynamoDBClient? getDbClient() => m_db_client;
}