164 lines
6.5 KiB
C#
164 lines
6.5 KiB
C#
using BrokerCore.DbEntity;
|
|
using BrokerCore.Entity;
|
|
using BrokerCore.Repository;
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
// using Polly;
|
|
// using Polly.Retry;
|
|
using MetaAssets;
|
|
|
|
using ServerCommon;
|
|
|
|
namespace BrokerCore.Services;
|
|
using Common;
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Storage;
|
|
using Repository.Context;
|
|
using ServerCore; using ServerBase;
|
|
|
|
//=========================================================================================
|
|
// 플래닛의 아이템을 칼리버스 재화로 교환하는 주문 생성
|
|
// Broker의 rdb(순수 교환 정보)와 DynamoDB(유저의 게임정보)를 사용하여 교환 주문을 생성한다.
|
|
// 유저의 게임 정보에서 재화가 차감되면
|
|
//=========================================================================================
|
|
public class CurrencyExchangeCreationStrategy : IOrderCreationStrategy
|
|
{
|
|
private readonly PlanetUserEntity m_planet_user_entity;
|
|
private readonly MetaverseBrokerDbContext m_broker_db_context;
|
|
private readonly PlanetItemExchangeOrderRepo m_planet_item_exchange_repo;
|
|
private readonly PlanetItemExchangeOrderAmountTotalLimitRepo m_planet_item_exchange_order_amount_total_limit;
|
|
private readonly PlanetItemExchangeOrderAmountUserLimitRepo m_planet_item_exchange_order_amount_user_limit;
|
|
private readonly DynamoDbClient m_dynamo_db_client;
|
|
private readonly EchoSystemService m_echo_system_service;
|
|
private readonly ILogger<CurrencyExchangeCreationStrategy>? m_logger;
|
|
|
|
public CurrencyExchangeCreationStrategy(
|
|
IServerLogic serverLogic,
|
|
PlanetUserEntity planetUserEntity,
|
|
MetaverseBrokerDbContext brokerDbContext,
|
|
PlanetItemExchangeOrderRepo planetItemExchangeRepo,
|
|
PlanetItemExchangeOrderAmountTotalLimitRepo planetItemExchangeOrderAmountTotalLimit,
|
|
PlanetItemExchangeOrderAmountUserLimitRepo planetItemExchangeOrderAmountUserLimit,
|
|
EchoSystemService echoSystemService,
|
|
ILogger<CurrencyExchangeCreationStrategy>? logger = null!)
|
|
{
|
|
m_planet_user_entity = planetUserEntity;
|
|
m_broker_db_context = brokerDbContext;
|
|
m_planet_item_exchange_repo = planetItemExchangeRepo;
|
|
m_planet_item_exchange_order_amount_total_limit = planetItemExchangeOrderAmountTotalLimit;
|
|
m_planet_item_exchange_order_amount_user_limit = planetItemExchangeOrderAmountUserLimit;
|
|
m_dynamo_db_client = serverLogic.getDynamoDbClient();
|
|
m_echo_system_service = echoSystemService;
|
|
m_logger = logger;
|
|
}
|
|
|
|
public async Task<(Result, PlanetItemExchangeOrder)> createOrder(
|
|
PlanetItemExchangeOrder order,
|
|
string planetServerType,
|
|
PlanetItemExchangePolicyMetaData exchangePolicy, CancellationToken cancellationToken = default)
|
|
{
|
|
var exchange_date = DateOnly.FromDateTime(order.CreatedAt.ToUniversalTime());
|
|
var exchange_amount = order.ExchangeMetaAmount;
|
|
var strategy = m_broker_db_context.Database.CreateExecutionStrategy();
|
|
var execute_result = await strategy.ExecuteAsync<Result>(async () =>
|
|
{
|
|
var transaction_result = new Result();
|
|
await using var transaction = await m_broker_db_context.Database.BeginTransactionAsync(cancellationToken);
|
|
try
|
|
{
|
|
var daily_limit_checker = new DailyAmountLimitChecker(
|
|
m_planet_item_exchange_order_amount_total_limit,
|
|
m_planet_item_exchange_order_amount_user_limit);
|
|
var (result, total_limit, user_limit) = await daily_limit_checker.dailyLimitCheck(order, exchangePolicy, cancellationToken);
|
|
|
|
// 신규 주문 정보 삽입
|
|
await m_planet_item_exchange_repo.add(order, cancellationToken);
|
|
Guard.Against.resultFail(result);
|
|
Guard.Against.isNull(total_limit, ServerErrorCode.RdbError,
|
|
()=>"PlanetItemExchangeOrderAmountTotalLimit not found");
|
|
Guard.Against.isNull(user_limit, ServerErrorCode.RdbError,
|
|
()=>"PlanetItemExchangeOrderAmountUserLimit not found");
|
|
|
|
var (currency_result, _) = await updateCurrency(exchange_amount, exchangePolicy);
|
|
Guard.Against.resultFail(currency_result);
|
|
|
|
await m_planet_item_exchange_order_amount_total_limit.increaseDailyAmount(total_limit,
|
|
exchange_amount, cancellationToken);
|
|
|
|
await m_planet_item_exchange_order_amount_user_limit.increaseDailyAmount(user_limit,
|
|
exchange_amount, cancellationToken);
|
|
|
|
await transaction.CommitAsync(cancellationToken);
|
|
|
|
// 사파이어 처리인 경우 에코시스템에 통보
|
|
if (string.Equals(exchangePolicy.CaliverseItemId, CurrencyType.Sapphire.ToString(),
|
|
StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var sapphire_delta = exchange_amount * exchangePolicy.CaliverseItemAmount;
|
|
_ = notifyToEchoSystemEvent(planetServerType, sapphire_delta).ConfigureAwait(false);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
if (transaction.GetDbTransaction().Connection is not null)
|
|
{
|
|
await transaction.RollbackAsync(cancellationToken);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
return transaction_result;
|
|
});
|
|
return (execute_result, order);
|
|
}
|
|
|
|
private async Task<(Result, long)> updateCurrency(
|
|
int exchangeMetaAmount,
|
|
PlanetItemExchangePolicyMetaData exchangePolicy)
|
|
{
|
|
var currency_delta = exchangeMetaAmount * exchangePolicy.CaliverseItemAmount;
|
|
CurrencyControlHelper.setDbConnector(m_dynamo_db_client);
|
|
var (result, current_sapphire_amount_double) =
|
|
await CurrencyControlHelper.spendMoneyByUserGuid(getUserGuid(), CurrencyType.Sapphire, currency_delta);
|
|
var current_sapphire_amount = Convert.ToInt64(current_sapphire_amount_double);
|
|
return (result, current_sapphire_amount);
|
|
}
|
|
|
|
//===========================================================================================
|
|
// 사파이어 처리인 경우 외부에 있는 에코시스템에 이벤트를 통보하여야 한다.
|
|
//===========================================================================================
|
|
private async Task notifyToEchoSystemEvent(
|
|
string planetServerType,
|
|
long sapphireDelta)
|
|
{
|
|
try
|
|
{
|
|
await m_echo_system_service.createAndSetEventPayload(
|
|
accountId: getUserAccountId(),
|
|
nickname: getUserNickname(),
|
|
userGuid: getUserGuid(),
|
|
sapphireDelta,
|
|
planetServerType,
|
|
CaliumEventType.extra_get.ToString()
|
|
);
|
|
|
|
_ = await m_echo_system_service.processCaliumEvent(m_planet_user_entity);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
m_logger?.LogError(ex, "Failed to process calium event");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
private string getUserAccountId() =>
|
|
m_planet_user_entity.getEntityAttributeNotNull<AccountAttribute>().AccountId;
|
|
|
|
private string getUserGuid() =>
|
|
m_planet_user_entity.getEntityAttributeNotNull<AccountAttribute>().UserGuid;
|
|
|
|
private string getUserNickname() =>
|
|
m_planet_user_entity.getEntityAttributeNotNull<NicknameAttribute>().Nickname;
|
|
}
|