1
0
mirror of synced 2024-12-21 02:35:53 +01:00
GC-local-server-rewrite/Application/Game/Card/OnlineMatching/StartOnlineMatchingCommand.cs
2023-02-27 02:43:13 +08:00

92 lines
3.8 KiB
C#

using Application.Common.Helpers;
using Domain.Entities;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.Extensions.Logging;
namespace Application.Game.Card.OnlineMatching;
public record StartOnlineMatchingCommand(long CardId, string Data) : IRequestWrapper<string>;
public class StartOnlineMatchingCommandHandler : RequestHandlerBase<StartOnlineMatchingCommand, string>
{
private const int MAX_RETRY = 5;
private const string MATCH_ENRTY_XPATH = "/root/online_matching";
private const string RECORD_XPATH = $"{MATCH_ENRTY_XPATH}/record";
private readonly ILogger<StartOnlineMatchingCommandHandler> logger;
public StartOnlineMatchingCommandHandler(ICardDependencyAggregate aggregate, ILogger<StartOnlineMatchingCommandHandler> logger) : base(aggregate)
{
this.logger = logger;
}
public override async Task<ServiceResult<string>> Handle(StartOnlineMatchingCommand request, CancellationToken cancellationToken)
{
var dto = request.Data.DeserializeCardData<OnlineMatchEntryDto>();
dto.CardId = request.CardId;
dto.StartTime = TimeHelper.CurrentTimeToString();
dto.MatchTimeout = 20;
dto.MatchRemainingTime = 5;
dto.MatchWaitTime = 5;
dto.Status = 1;
var entry = dto.DtoToOnlineMatchEntry();
var matchId = await CardDbContext.OnlineMatches.CountAsync(cancellationToken);
for (int i = 0; i < MAX_RETRY; i++)
{
try
{
var onlineMatch = await CardDbContext.OnlineMatches
.Include(match => match.Entries)
.FirstOrDefaultAsync(match => match.IsOpen && match.Entries.Count < 4, cancellationToken);
string result;
if (onlineMatch is not null)
{
entry.EntryId = onlineMatch.Entries.Count;
onlineMatch.Entries.Add(entry);
onlineMatch.Guid = Guid.NewGuid();
await CardDbContext.SaveChangesAsync(cancellationToken);
result = onlineMatch.Entries.Select((matchEntry, id) =>
{
var entryDto = matchEntry.OnlineMatchEntryToDto();
entryDto.Id = id;
return entryDto;
}).SerializeCardDataList(RECORD_XPATH);
return new ServiceResult<string>(result);
}
entry.EntryId = 0;
onlineMatch = new OnlineMatch
{
MatchId = matchId,
Entries = { entry },
Guid = Guid.NewGuid(),
IsOpen = true
};
CardDbContext.OnlineMatches.Add(onlineMatch);
await CardDbContext.SaveChangesAsync(cancellationToken);
result = onlineMatch.Entries.Select((matchEntry, id) =>
{
var entryDto = matchEntry.OnlineMatchEntryToDto();
entryDto.Id = id;
return entryDto;
}).SerializeCardDataList(RECORD_XPATH);
return new ServiceResult<string>(result);
}
catch (DbUpdateConcurrencyException e)
{
logger.LogWarning(e, "Concurrent DB update when starting online match");
}
catch (DbUpdateException e)
when (e.InnerException != null
&& e.InnerException.Message.StartsWith("Cannot insert duplicate key row in object"))
{
logger.LogWarning(e, "Concurrent insert when starting online match");
}
}
logger.LogError("Cannot update DB after {Number} trials for online match!", MAX_RETRY);
return ServiceResult.Failed<string>(ServiceError.DatabaseSaveFailed);
}
}