using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.DocumentModel; using Amazon.DynamoDBv2.Model; using Amazon.S3.Model; using ServerCore; using ServerBase; using DYNAMO_DB_TABLE_NAME = System.String; using DYNAMO_DB_TABLE_FULL_NAME = System.String; using USER_GUID = System.String; namespace ServerCommon; public static class CurrencyControlHelper { private static DynamoDbClient? m_db_connector = null; //============================================================================================= // 단위당 금전량을 quantity 만큼 계산하여 Round 보정후 반환 한다. //============================================================================================= public static double calculateRoundedMoneyByCurrency(this double reqUnitMoney, CurrencyType currencyType, int quantity = 1) { var result = new Result(); if (ServerCore.TypeHelper.NumericSignType.Positive == ServerCore.TypeHelper.checkNumericSignType(reqUnitMoney)) { reqUnitMoney *= -1; } var req_money = reqUnitMoney * quantity; return roundMoneyByCurrencyType(currencyType, req_money); } //============================================================================================= // 금전량을 보정 한다. //============================================================================================= public static double roundMoneyByCurrencyType(CurrencyType currencyType, double delta) { // CurrencyType.Calium 이 아닌 모든 재화는 소숫점을 올림 처리 한다 !!! if (currencyType != CurrencyType.Calium) { delta = MathHelper.roundUpOrDown(delta); } return delta; } //============================================================================================= // delta 만큼 금전을 쓴다. //============================================================================================= public static async Task<(Result, double)> spendMoneyByUserGuid( USER_GUID userGuid, CurrencyType currencyType, double delta ) { var result = new Result(); if (ServerCore.TypeHelper.NumericSignType.Positive == ServerCore.TypeHelper.checkNumericSignType(delta)) { delta *= -1; } return await changeMoneyByUserGuid(userGuid, currencyType, delta); } //============================================================================================= // delta 만큼 금전을 얻는다. //============================================================================================= public static async Task<(Result, double)> earnMoneyByUserGuid(USER_GUID userGuid, CurrencyType currencyType, double delta) { var result = new Result(); if (ServerCore.TypeHelper.NumericSignType.Negative == ServerCore.TypeHelper.checkNumericSignType(delta)) { delta *= -1; } if (0 < delta) { return await changeMoneyByUserGuid(userGuid, currencyType, delta); } return (result, 0); } public static async Task<(Result, double)> getMoneyByUserGuid(USER_GUID userGuid, CurrencyType type) { var result = new Result(); string err_msg; var error_code = hasDbConnector(); if (error_code.isFail()) { err_msg = $"Not available DynamoDB connector !!! : userGuid:{userGuid}"; result.setFail(error_code, err_msg); return (result, 0); } var db_connector = getDbConnector(); (result, var found_money_doc) = await findMoneyDocByUserGuid(db_connector, userGuid); if (null == found_money_doc) { err_msg = $"Not found MoneyDoc !!! : userGuid:{userGuid}"; result.setFail(ServerErrorCode.MoneyDocIsNull, err_msg); return (result, 0); } var attrib = found_money_doc.getAttrib(); NullReferenceCheckHelper.throwIfNull(attrib, () => $"attrib is null !!!"); return (result, attrib.getCurrencyFromType(type)); } public static async Task<(Result, double)> changeMoneyByUserGuid(USER_GUID userGuid, CurrencyType type, double delta) { var result = new Result(); var err_msg = string.Empty; var error_code = hasDbConnector(); if (error_code.isFail()) { err_msg = $"Not available DynamoDB connector !!! : userGuid:{userGuid}"; result.setFail(error_code, err_msg); return (result, 0); } var db_connector = getDbConnector(); var table = db_connector.getTableByDoc(); (result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(userGuid); if (result.isFail()) { return (result, 0); } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - userGuid:{userGuid}"); (result, var request) = makeUpdateItemRequest( table.TableName , make_primary_key.toKeyWithAttributeValue(), MoneyAttribExtensions.getKeyNameFromType(type) , delta); if (result.isFail() || request == null) return (result, 0); (result, var changed_money_doc) = await db_connector.simpleQueryDocTypesWithUpdateItemRequest(request); if (result.isFail() || changed_money_doc == null) return (result, 0); var money_attrib = changed_money_doc.getAttrib(); NullReferenceCheckHelper.throwIfNull(money_attrib, () => $"money_attrib is null !!! - userGuid:{userGuid}"); return (result, money_attrib.getCurrencyFromType(type)); } public static async Task<(Result, MoneyDoc?)> findMoneyDocByUserGuid(DynamoDbClient dynamoDbClient, USER_GUID userGuid) { var result = new Result(); var money_doc = new MoneyDoc(); money_doc.setCombinationKeyForPK(userGuid); money_doc.onApplyPKSK(); var query_config = dynamoDbClient.makeQueryConfigForReadByPKOnly(money_doc.getPK()); return await dynamoDbClient.simpleQueryDocTypeWithQueryOperationConfig(query_config); } private static (Result, UpdateItemRequest?) makeUpdateItemRequest( DYNAMO_DB_TABLE_FULL_NAME tableFullName , Dictionary attributeValueWithPrimaryKey , string targetAttribName , double deltaCount ) { var result = new Result(); var err_msg = string.Empty; var error_code = hasDbConnector(); if (error_code.isFail()) { err_msg = $"Not available DynamoDb connector !!!"; result.setFail(error_code, err_msg); return (result, null); } var query_builder = new DynamoDbItemRequestHelper.UpdateItemRequestBuilder(tableFullName); query_builder.withKeys(attributeValueWithPrimaryKey); var target_doc = new MoneyDoc(); var attrib_path_json_string = target_doc.toJsonStringOfAttribs(); var target_key = JsonHelper.getJsonPropertyName(targetAttribName); (var is_success, var attribute_expression) = DynamoDbClientHelper.toAttributeExpressionFromJson(attrib_path_json_string, target_key); if (false == is_success) { err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : attribPath:{attrib_path_json_string}, targetKey:{target_key}"; result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg); Log.getLogger().error(result.toBasicString()); return (result, null); } query_builder.withExpressionAttributeNames(DynamoDbClientHelper.toExpressionAttributeNamesFromJson(attrib_path_json_string, target_key)); var update_expression = (deltaCount >= 0) ? $"SET {attribute_expression} = if_not_exists({attribute_expression}, :start) + :changeValue" : $"SET {attribute_expression} = if_not_exists({attribute_expression}, :start) - :changeValue"; query_builder.withUpdateExpression(update_expression); var expression_attribute_values = new Dictionary { { ":changeValue", new AttributeValue { N = Math.Abs(deltaCount).ToString() } }, { ":start", new AttributeValue { N = "0" } } }; query_builder.withExpressionAttributeValues(expression_attribute_values); query_builder.withReturnValues(ReturnValue.ALL_NEW); return query_builder.build(); } private static ServerErrorCode hasDbConnector() { if(null == m_db_connector) { return ServerErrorCode.DynamoDbConnectorIsNull; } return ServerErrorCode.Success; } public static DynamoDbClient getDbConnector() { NullReferenceCheckHelper.throwIfNull(m_db_connector, () => $"m_db_connector is null !!!"); return m_db_connector; } //============================================================================================= // CurrencyControlHelper <= DynamoDbClient 설정 //============================================================================================= public static Result setDbConnector(DynamoDbClient dbConnector) { var result = new Result(); m_db_connector = dbConnector; return result; } }