From 7093997658f4561f225beb4074a2e4c3e2c9a373 Mon Sep 17 00:00:00 2001 From: asesidaa <1061472754@qq.com> Date: Sat, 11 Feb 2023 01:24:24 +0800 Subject: [PATCH] Add stubs for online mathcing and writing --- Application/Application.csproj | 2 - .../StartOnlineMatchingCommand.cs | 6 + .../UpdateOnlineMatchingCommand.cs | 6 + .../UploadOnlineMatchingResultCommand.cs | 6 + .../Game/Card/Write/WriteAvatarCommand.cs | 17 ++ .../Game/Card/Write/WriteCoinCommand.cs | 17 ++ .../Game/Card/Write/WriteItemCommand.cs | 17 ++ .../Card/Write/WriteMusicDetailCommand.cs | 17 ++ .../Game/Card/Write/WriteNavigatorCommand.cs | 17 ++ .../Game/Card/Write/WriteSkinCommand.cs | 17 ++ .../Card/Write/WriteSoundEffectCommand.cs | 17 ++ .../Game/Card/Write/WriteTitleCommand.cs | 17 ++ .../Card/Write/WriteUnlockKeynumCommand.cs | 17 ++ GC-local-server-rewrite/common/Configs.cs | 10 ++ GC-local-server-rewrite/common/Converters.cs | 61 ++++++++ .../common/IAppSettings.cs | 3 + GC-local-server-rewrite/config.json | 5 +- .../controllers/CardServiceController.cs | 145 +++++++++++------- MatchServer/Controllers/MatchingController.cs | 131 ++++++++++++++++ MatchServer/MatchServer.csproj | 17 ++ MatchServer/Program.cs | 21 +++ MatchServer/Properties/launchSettings.json | 31 ++++ MatchServer/Storage/MatchingDb.cs | 22 +++ MatchServer/appsettings.Development.json | 8 + MatchServer/appsettings.json | 9 ++ SharedProject/models/OnlineMatchingData.cs | 44 ++++++ .../models/OnlineMatchingFinishRequest.cs | 8 + .../models/OnlineMatchingUpdateRequest.cs | 14 ++ 28 files changed, 641 insertions(+), 61 deletions(-) create mode 100644 Application/Game/Card/OnlineMatching/StartOnlineMatchingCommand.cs create mode 100644 Application/Game/Card/OnlineMatching/UpdateOnlineMatchingCommand.cs create mode 100644 Application/Game/Card/OnlineMatching/UploadOnlineMatchingResultCommand.cs create mode 100644 Application/Game/Card/Write/WriteAvatarCommand.cs create mode 100644 Application/Game/Card/Write/WriteCoinCommand.cs create mode 100644 Application/Game/Card/Write/WriteItemCommand.cs create mode 100644 Application/Game/Card/Write/WriteMusicDetailCommand.cs create mode 100644 Application/Game/Card/Write/WriteNavigatorCommand.cs create mode 100644 Application/Game/Card/Write/WriteSkinCommand.cs create mode 100644 Application/Game/Card/Write/WriteSoundEffectCommand.cs create mode 100644 Application/Game/Card/Write/WriteTitleCommand.cs create mode 100644 Application/Game/Card/Write/WriteUnlockKeynumCommand.cs create mode 100644 GC-local-server-rewrite/common/Converters.cs create mode 100644 MatchServer/Controllers/MatchingController.cs create mode 100644 MatchServer/MatchServer.csproj create mode 100644 MatchServer/Program.cs create mode 100644 MatchServer/Properties/launchSettings.json create mode 100644 MatchServer/Storage/MatchingDb.cs create mode 100644 MatchServer/appsettings.Development.json create mode 100644 MatchServer/appsettings.json create mode 100644 SharedProject/models/OnlineMatchingData.cs create mode 100644 SharedProject/models/OnlineMatchingFinishRequest.cs create mode 100644 SharedProject/models/OnlineMatchingUpdateRequest.cs diff --git a/Application/Application.csproj b/Application/Application.csproj index 4fb7069..81ec46e 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -22,9 +22,7 @@ - - diff --git a/Application/Game/Card/OnlineMatching/StartOnlineMatchingCommand.cs b/Application/Game/Card/OnlineMatching/StartOnlineMatchingCommand.cs new file mode 100644 index 0000000..15a91b2 --- /dev/null +++ b/Application/Game/Card/OnlineMatching/StartOnlineMatchingCommand.cs @@ -0,0 +1,6 @@ +namespace Application.Game.Card.OnlineMatching; + +public class StartOnlineMatchingCommand +{ + +} \ No newline at end of file diff --git a/Application/Game/Card/OnlineMatching/UpdateOnlineMatchingCommand.cs b/Application/Game/Card/OnlineMatching/UpdateOnlineMatchingCommand.cs new file mode 100644 index 0000000..0893cab --- /dev/null +++ b/Application/Game/Card/OnlineMatching/UpdateOnlineMatchingCommand.cs @@ -0,0 +1,6 @@ +namespace Application.Game.Card.OnlineMatching; + +public class UpdateOnlineMatchingCommand +{ + +} \ No newline at end of file diff --git a/Application/Game/Card/OnlineMatching/UploadOnlineMatchingResultCommand.cs b/Application/Game/Card/OnlineMatching/UploadOnlineMatchingResultCommand.cs new file mode 100644 index 0000000..00075ee --- /dev/null +++ b/Application/Game/Card/OnlineMatching/UploadOnlineMatchingResultCommand.cs @@ -0,0 +1,6 @@ +namespace Application.Game.Card.OnlineMatching; + +public class UploadOnlineMatchingResultCommand +{ + +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteAvatarCommand.cs b/Application/Game/Card/Write/WriteAvatarCommand.cs new file mode 100644 index 0000000..fa07503 --- /dev/null +++ b/Application/Game/Card/Write/WriteAvatarCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteAvatarCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteAvatarCommandHandler : CardRequestHandlerBase +{ + public WriteAvatarCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteAvatarCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteCoinCommand.cs b/Application/Game/Card/Write/WriteCoinCommand.cs new file mode 100644 index 0000000..c3b17ac --- /dev/null +++ b/Application/Game/Card/Write/WriteCoinCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteCoinCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteCoinCommandHandler : CardRequestHandlerBase +{ + public WriteCoinCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteCoinCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteItemCommand.cs b/Application/Game/Card/Write/WriteItemCommand.cs new file mode 100644 index 0000000..ee58212 --- /dev/null +++ b/Application/Game/Card/Write/WriteItemCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteItemCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteItemCommandHandler : CardRequestHandlerBase +{ + public WriteItemCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteItemCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteMusicDetailCommand.cs b/Application/Game/Card/Write/WriteMusicDetailCommand.cs new file mode 100644 index 0000000..346e070 --- /dev/null +++ b/Application/Game/Card/Write/WriteMusicDetailCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteMusicDetailCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteMusicDetailCommandHandler : CardRequestHandlerBase +{ + public WriteMusicDetailCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteMusicDetailCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteNavigatorCommand.cs b/Application/Game/Card/Write/WriteNavigatorCommand.cs new file mode 100644 index 0000000..0629348 --- /dev/null +++ b/Application/Game/Card/Write/WriteNavigatorCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteNavigatorCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteNavigatorCommandHandler : CardRequestHandlerBase +{ + public WriteNavigatorCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteNavigatorCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteSkinCommand.cs b/Application/Game/Card/Write/WriteSkinCommand.cs new file mode 100644 index 0000000..ecc1102 --- /dev/null +++ b/Application/Game/Card/Write/WriteSkinCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteSkinCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteSkinCommandHandler : CardRequestHandlerBase +{ + public WriteSkinCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteSkinCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteSoundEffectCommand.cs b/Application/Game/Card/Write/WriteSoundEffectCommand.cs new file mode 100644 index 0000000..955b8b9 --- /dev/null +++ b/Application/Game/Card/Write/WriteSoundEffectCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteSoundEffectCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteSoundEffectCommandHandler : CardRequestHandlerBase +{ + public WriteSoundEffectCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteSoundEffectCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteTitleCommand.cs b/Application/Game/Card/Write/WriteTitleCommand.cs new file mode 100644 index 0000000..2b0ccca --- /dev/null +++ b/Application/Game/Card/Write/WriteTitleCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteTitleCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteTitleCommandHandler : CardRequestHandlerBase +{ + public WriteTitleCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteTitleCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/Application/Game/Card/Write/WriteUnlockKeynumCommand.cs b/Application/Game/Card/Write/WriteUnlockKeynumCommand.cs new file mode 100644 index 0000000..040399a --- /dev/null +++ b/Application/Game/Card/Write/WriteUnlockKeynumCommand.cs @@ -0,0 +1,17 @@ +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Card.Write; + +public record WriteUnlockKeynumCommand(long CardId, string Data) : IRequestWrapper; + +public class WriteUnlockKeynumCommandHandler : CardRequestHandlerBase +{ + public WriteUnlockKeynumCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {} + + public override Task> Handle(WriteUnlockKeynumCommand request, CancellationToken cancellationToken) + { + // TODO: Add proper implementation + return Task.FromResult(new ServiceResult(request.Data)); + } +} \ No newline at end of file diff --git a/GC-local-server-rewrite/common/Configs.cs b/GC-local-server-rewrite/common/Configs.cs index dc7a7eb..b8bd31e 100644 --- a/GC-local-server-rewrite/common/Configs.cs +++ b/GC-local-server-rewrite/common/Configs.cs @@ -141,6 +141,14 @@ public static class Configs public const int SCORE_PCOL1 = 21; + public const string MATCHING_URL_BASE = "Matching"; + + public const string START_MATCHING_URL = "Start"; + public const string UPDATE_MATCHING_URL = "Update"; + public const string FINISH_MATCHING_URL = "Finish"; + + + public static readonly List DOMAINS = new() { "localhost", @@ -164,6 +172,8 @@ public static class Configs public const string DEFAULT_RELAY_SERVER = "127.0.0.1"; public const int DEFAULT_RELAY_PORT = 54321; public const string DEFAULT_EVENT_FOLDER = "event"; + public const string DEFAULT_MATCHING_SERVER = "127.0.0.1:5000"; + public static readonly IReadOnlyList DEFAULT_UNLOCKABLE_SONGS = new[] { diff --git a/GC-local-server-rewrite/common/Converters.cs b/GC-local-server-rewrite/common/Converters.cs new file mode 100644 index 0000000..e1d9bbf --- /dev/null +++ b/GC-local-server-rewrite/common/Converters.cs @@ -0,0 +1,61 @@ +using GCLocalServerRewrite.models; +using SharedProject.models; + +namespace GCLocalServerRewrite.common; + +public static class Converters +{ + public static OnlineMatchingData ConvertFromEntry(OnlineMatchingEntry entry) + { + return new OnlineMatchingData + { + AvatarId = entry.AvatarId, + CardId = entry.CardId, + ClassId = entry.ClassId, + EntryNo = entry.EntryNo, + EntryStart = entry.EntryStart, + EventId = entry.EventId, + GroupId = entry.GroupId, + MachineId = entry.MachineId, + MatchingId = entry.MatchingId, + MatchingRemainingTime = entry.MatchingRemainingTime, + Pref = entry.Pref, + Status = entry.Status, + MatchingTimeout = entry.MatchingTimeout, + MessageId = entry.MessageId, + PlayerName = entry.PlayerName, + PrefId = entry.PrefId, + TenpoId = entry.TenpoId, + TenpoName = entry.TenpoName, + TitleId = entry.TitleId, + MatchingWaitTime = entry.MatchingWaitTime + }; + } + + public static OnlineMatchingEntry ConvertFromData(OnlineMatchingData entry) + { + return new OnlineMatchingEntry + { + AvatarId = entry.AvatarId, + CardId = entry.CardId, + ClassId = entry.ClassId, + EntryNo = entry.EntryNo, + EntryStart = entry.EntryStart, + EventId = entry.EventId, + GroupId = entry.GroupId, + MachineId = entry.MachineId, + MatchingId = entry.MatchingId, + MatchingRemainingTime = entry.MatchingRemainingTime, + Pref = entry.Pref, + Status = entry.Status, + MatchingTimeout = entry.MatchingTimeout, + MessageId = entry.MessageId, + PlayerName = entry.PlayerName, + PrefId = entry.PrefId, + TenpoId = entry.TenpoId, + TenpoName = entry.TenpoName, + TitleId = entry.TitleId, + MatchingWaitTime = entry.MatchingWaitTime + }; + } +} \ No newline at end of file diff --git a/GC-local-server-rewrite/common/IAppSettings.cs b/GC-local-server-rewrite/common/IAppSettings.cs index 31b77a9..250297a 100644 --- a/GC-local-server-rewrite/common/IAppSettings.cs +++ b/GC-local-server-rewrite/common/IAppSettings.cs @@ -43,6 +43,9 @@ public interface IAppSettings [Option(DefaultValue = false)] bool DownloadEvents { get; } + [Option(DefaultValue = Configs.DEFAULT_MATCHING_SERVER)] + string MatchingServer { get; } + [Option(DefaultValue = null)] IEnumerable? UnlockableSongIds { get; } diff --git a/GC-local-server-rewrite/config.json b/GC-local-server-rewrite/config.json index 14a1bed..0bf89e7 100644 --- a/GC-local-server-rewrite/config.json +++ b/GC-local-server-rewrite/config.json @@ -11,7 +11,8 @@ "EventFolder": "event", "DownloadEvents": false, "RelayServer": "127.0.0.1", - "RelayPort": 54321, + "RelayPort": 3333, + "MatchingServer": "127.0.0.1:5038", "UnlockableSongIds": [ 11, 13, @@ -68,7 +69,7 @@ "FileName": "/event_103_20201125.evt", "NotBeforeUnixTime": 1335677127, "NotAfterUnixTime": 1966397127, - "Md5": "9ef6c4d5ca381583a2d99b626ce06b5e", + "Md5": "27b503145a62e46f5f611b6f8a91e4f3", "Index": 0 }, { diff --git a/GC-local-server-rewrite/controllers/CardServiceController.cs b/GC-local-server-rewrite/controllers/CardServiceController.cs index b279469..f36d411 100644 --- a/GC-local-server-rewrite/controllers/CardServiceController.cs +++ b/GC-local-server-rewrite/controllers/CardServiceController.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Net.Http.Json; using System.Net.Mime; using System.Text; using System.Xml.Linq; @@ -8,9 +8,13 @@ using EmbedIO.Routing; using EmbedIO.WebApi; using GCLocalServerRewrite.common; using GCLocalServerRewrite.models; +using SharedProject.models; using SQLite.Net2; using Swan; using Swan.Logging; +using Avatar=GCLocalServerRewrite.models.Avatar; +using Navigator=GCLocalServerRewrite.models.Navigator; +using Title=GCLocalServerRewrite.models.Title; namespace GCLocalServerRewrite.controllers; @@ -19,13 +23,6 @@ public class CardServiceController : WebApiController private readonly SQLiteConnection cardSqLiteConnection; private readonly SQLiteConnection musicSqLiteConnection; - private static readonly ConcurrentDictionary> OnlineMatchingEntries = new() - { - [0xDEADBEEF] = new List(), - [0xCAFEBABE] = new List(), - [0xD0D0CACA] = new List() - }; - public CardServiceController() { cardSqLiteConnection = DatabaseHelper.ConnectDatabase(Configs.SETTINGS.CardDbName); @@ -34,17 +31,17 @@ public class CardServiceController : WebApiController [Route(HttpVerbs.Post, "/cardn.cgi")] // ReSharper disable once UnusedMember.Global - public string CardService([FormField] int gid, [FormField("mac_addr")] string mac, [FormField] int type, + public async Task CardService([FormField] int gid, [FormField("mac_addr")] string mac, [FormField] int type, [FormField("card_no")] long cardId, [FormField("data")] string xmlData, [FormField("cmd_str")] int cmdType) { HttpContext.Response.ContentType = MediaTypeNames.Application.Octet; HttpContext.Response.ContentEncoding = new UTF8Encoding(false); HttpContext.Response.KeepAlive = true; - return ProcessCommand(cmdType, mac, cardId, xmlData, type); + return await ProcessCommand(cmdType, mac, cardId, xmlData, type); } - private string ProcessCommand(int cmdType, string mac, long cardId, string xmlData, int type) + private async Task ProcessCommand(int cmdType, string mac, long cardId, string xmlData, int type) { if (!Enum.IsDefined(typeof(Command), cmdType)) { @@ -55,7 +52,7 @@ public class CardServiceController : WebApiController return command switch { - Command.CardReadRequest or Command.CardWriteRequest => ProcessCardRequest(mac, cardId, xmlData, type), + Command.CardReadRequest or Command.CardWriteRequest => await ProcessCardRequest(mac, cardId, xmlData, type), Command.ReissueRequest => ProcessReissueRequest(), Command.RegisterRequest => ProcessRegisterRequest(cardId, xmlData), _ => throw new ArgumentOutOfRangeException(nameof(command), command, "Command unknown, should never happen!") @@ -75,7 +72,7 @@ public class CardServiceController : WebApiController return ConstructResponse("", ReturnCode.NotReissue); } - private string ProcessCardRequest(string mac, long cardId, string xmlData, int type) + private async Task ProcessCardRequest(string mac, long cardId, string xmlData, int type) { if (!Enum.IsDefined(typeof(CardRequestType), type)) { @@ -230,19 +227,22 @@ public class CardServiceController : WebApiController case CardRequestType.StartOnlineMatching: { $"Start Online Matching, data is {xmlData}".Info(); - return ConstructResponse(StartOnlineMatching(cardId, xmlData)); + var resultString = await StartOnlineMatching(cardId, xmlData); + return ConstructResponse(resultString); } case CardRequestType.UpdateOnlineMatching: { $"Update Online Matching, data is {xmlData}".Info(); - return ConstructResponse(UpdateOnlineMatching(cardId, xmlData)); + var resultString = await UpdateOnlineMatching(cardId, xmlData); + return ConstructResponse(resultString); } case CardRequestType.UploadOnlineMatchingResult: { $"Get Online Matching result, data is {xmlData}".Info(); - return ConstructResponse(UploadOnlineMatchingResult(cardId, xmlData)); + var resultString = await UploadOnlineMatchingResult(cardId, xmlData); + return ConstructResponse(resultString); } #endregion @@ -618,67 +618,98 @@ public class CardServiceController : WebApiController #region OnlineMatchingImplementation - private static string StartOnlineMatching(long cardId, string xmlData) + private static async Task StartOnlineMatching(long cardId, string xmlData) { var reader = new ChoXmlReader(new StringReader(xmlData)).WithXPath(Configs.DATA_XPATH); var entry = reader.Read(); - entry.CardId = cardId; - entry.MatchingId = 0xDEADBEEF; - entry.EntryNo = OnlineMatchingEntries[0xDEADBEEF].Count; - entry.EntryStart = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); - entry.MatchingTimeout = 20; - entry.MatchingRemainingTime = 3; - entry.MatchingWaitTime = 10; - entry.Status = 1; - entry.Dump().Info(); - var entries = OnlineMatchingEntries[0xDEADBEEF]; - var existing = entries.Find(matchingEntry => matchingEntry.CardId == cardId); - if (existing is not null) + var request = Converters.ConvertFromEntry(entry) ; + request.CardId = cardId; + request.EntryStart = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + request.MatchingTimeout = 20; + request.MatchingRemainingTime = 3; + request.MatchingWaitTime = 10; + request.Status = 1; + + var client = new HttpClient(); + var url = $"http://{Configs.SETTINGS.MatchingServer}/{Configs.MATCHING_URL_BASE}/{Configs.START_MATCHING_URL}"; + try { - "Card id already exist in entry! Previous match is not cleaned up! Clearing now".Warn(); - entries.Clear(); + var response = await client.PostAsJsonAsync(url, request); + var dataList = await response.Content.ReadFromJsonAsync>(); + if (dataList is null) + { + throw new HttpRequestException("Start matching request fail"); + } + var result = dataList.ConvertAll(input => Converters.ConvertFromData(input)); + return GenerateRecordsXml(result, Configs.ONLINE_MATCHING_XPATH); + } + catch (Exception e) + { + e.Error("", "Http request failed"); + throw; } - OnlineMatchingEntries[0xDEADBEEF].Add(entry); - - return GenerateRecordsXml(OnlineMatchingEntries[0xDEADBEEF], Configs.ONLINE_MATCHING_XPATH); } - private static string UpdateOnlineMatching(long cardId, string xmlData) + private static async Task UpdateOnlineMatching(long cardId, string xmlData) { var reader = new ChoXmlReader(new StringReader(xmlData)); var data = reader.Read(); - var entries = OnlineMatchingEntries[0xDEADBEEF]; - var entry = entries.Find(matchingEntry => matchingEntry.CardId == cardId); - if (entry is null) + var request = new OnlineMatchingUpdateRequest { - throw new HttpException(400,"Entry for this card id does not exist!"); - } - if (data.Action != 0) + Action = data.Action, + CardId = cardId, + EventId = data.EventId, + MatchingId = data.MatchingId, + MessageId = data.MessageId + }; + var client = new HttpClient(); + var url = $"http://{Configs.SETTINGS.MatchingServer}/{Configs.MATCHING_URL_BASE}/{Configs.UPDATE_MATCHING_URL}"; + try { - $"Action is {data.Action}".Info(); + var response = await client.PostAsJsonAsync(url, request); + var dataList = await response.Content.ReadFromJsonAsync>(); + if (dataList is null) + { + throw new HttpRequestException("Update matching request fail"); + } + return GenerateRecordsXml(dataList, Configs.ONLINE_MATCHING_XPATH); } - - entry.MessageId = data.MessageId; - if (entry.MatchingRemainingTime <= 0) + catch (Exception e) { - entry.Status = 3; - entry.Dump().Info(); - return GenerateRecordsXml(OnlineMatchingEntries[0xDEADBEEF], Configs.ONLINE_MATCHING_XPATH); + e.Error("", "Http request failed"); + throw; } - - entry.MatchingRemainingTime--; - entry.Dump().Info(); - - return GenerateRecordsXml(OnlineMatchingEntries[0xDEADBEEF], Configs.ONLINE_MATCHING_XPATH); } - private static string UploadOnlineMatchingResult(long cardId, string xmlData) + private static async Task UploadOnlineMatchingResult(long cardId, string xmlData) { var reader = new ChoXmlReader(new StringReader(xmlData)); var data = reader.Read(); - - var entries = OnlineMatchingEntries[0xDEADBEEF]; + var request = new OnlineMatchingFinishRequest + { + CardId = cardId, + MatchingId = data.MatchingId + }; + var client = new HttpClient(); + var url = $"http://{Configs.SETTINGS.MatchingServer}/{Configs.MATCHING_URL_BASE}/{Configs.UPDATE_MATCHING_URL}"; + try + { + var response = await client.PostAsJsonAsync(url, request); + var success = await response.Content.ReadFromJsonAsync(); + + var result = new OnlineMatchingResult + { + Status = success ? 1:0 + }; + return GenerateSingleXml(result, Configs.ONLINE_BATTLE_RESULT_XPATH); + } + catch (Exception e) + { + e.Error("", "Http request failed"); + throw; + } + /*var entries = OnlineMatchingEntries[0xDEADBEEF]; var entry = entries.Find(matchingEntry => matchingEntry.CardId == cardId); if (entry is null) { @@ -695,7 +726,7 @@ public class CardServiceController : WebApiController { Status = 1 }; - return GenerateSingleXml(result, Configs.ONLINE_BATTLE_RESULT_XPATH); + return GenerateSingleXml(result, Configs.ONLINE_BATTLE_RESULT_XPATH);*/ } #endregion diff --git a/MatchServer/Controllers/MatchingController.cs b/MatchServer/Controllers/MatchingController.cs new file mode 100644 index 0000000..2acb165 --- /dev/null +++ b/MatchServer/Controllers/MatchingController.cs @@ -0,0 +1,131 @@ +using MatchServer.Storage; +using Microsoft.AspNetCore.Mvc; +using SharedProject.models; + +namespace MatchServer.Controllers; + +[ApiController] +[Route("[controller]")] +public class MatchingController : ControllerBase +{ + private readonly ILogger logger; + + + public MatchingController(ILogger logger) { + this.logger = logger; + } + + [HttpPost("Start")] + public ActionResult> StartOnlineMatching(OnlineMatchingData startData) + { + logger.LogInformation("Start matching, card id {CardId}, player name {PlayerName}", startData.CardId, startData.PlayerName); + var matchingDb = MatchingDb.GetInstance; + + lock (matchingDb.DbLock) + { + foreach (var (matchingId, entries) in matchingDb.MatchingDictionary) + { + if (entries.Count >= 4) + { + continue; + } + + if (entries.Any(data => data.CardId == startData.CardId)) + { + logger.LogWarning("Card id {CardId} already exists in matching id {MatchingId}", startData.CardId, matchingId); + continue; + } + + entries.Add(startData); + startData.MatchingId = matchingId; + startData.EntryNo = entries.Count - 1; + break; + } + + if (startData.MatchingId != 0) + { + return Ok(matchingDb.MatchingDictionary[startData.MatchingId]); + } + + startData.MatchingId = matchingDb.MatchingDictionary.Count + 1; + startData.EntryNo = 0; + matchingDb.MatchingDictionary[startData.MatchingId] = new List + { + startData + }; + + return Ok(matchingDb.MatchingDictionary[startData.MatchingId]); + } + } + + [HttpPost("Update")] + public ActionResult> UpdateOnlineMatching(OnlineMatchingUpdateRequest updateData) + { + var matchingDb = MatchingDb.GetInstance; + var matchingId = updateData.MatchingId; + + logger.LogInformation("Update matching, card id is {CardId}, matching id is {MatchingId}", updateData.CardId, updateData.MatchingId); + + if (!matchingDb.MatchingDictionary.ContainsKey(matchingId)) + { + return BadRequest(); + } + + var dataList = matchingDb.MatchingDictionary[matchingId]; + + var data = dataList.Find(data => data.CardId == updateData.CardId); + if (data is null) + { + return BadRequest(); + } + + data.MessageId = updateData.MessageId; + if (data.MatchingRemainingTime <= 0) + { + data.Status = 3; + return Ok(dataList); + } + + data.MatchingRemainingTime--; + return Ok(dataList); + } + + [HttpPost("Finish")] + public ActionResult FinishOnlineMatching(OnlineMatchingFinishRequest request) + { + var matchingDb = MatchingDb.GetInstance; + var matchingId = request.MatchingId; + + lock (matchingDb.DbLock) + { + if (!matchingDb.MatchingDictionary.ContainsKey(matchingId)) + { + return BadRequest(); + } + var dataList = matchingDb.MatchingDictionary[matchingId]; + + var index = dataList.FindIndex(data => data.CardId == request.CardId); + dataList.RemoveAt(index); + } + return Ok(true); + } + + [HttpGet("Debug")] + public ActionResult>> InspectOnlineMatching() + { + var matchingDb = MatchingDb.GetInstance; + + return Ok(matchingDb.MatchingDictionary); + } + + [HttpGet("Clear")] + public ActionResult Clear() + { + var matchingDb = MatchingDb.GetInstance; + lock (matchingDb.DbLock) + { + matchingDb.MatchingDictionary.Clear(); + } + return Ok(true); + } +} \ No newline at end of file diff --git a/MatchServer/MatchServer.csproj b/MatchServer/MatchServer.csproj new file mode 100644 index 0000000..a40166b --- /dev/null +++ b/MatchServer/MatchServer.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/MatchServer/Program.cs b/MatchServer/Program.cs new file mode 100644 index 0000000..6d3cc9c --- /dev/null +++ b/MatchServer/Program.cs @@ -0,0 +1,21 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.MapControllers(); + +app.Run(); \ No newline at end of file diff --git a/MatchServer/Properties/launchSettings.json b/MatchServer/Properties/launchSettings.json new file mode 100644 index 0000000..22561dc --- /dev/null +++ b/MatchServer/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:45319", + "sslPort": 44313 + } + }, + "profiles": { + "MatchServer": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7023;http://localhost:5038", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/MatchServer/Storage/MatchingDb.cs b/MatchServer/Storage/MatchingDb.cs new file mode 100644 index 0000000..16656d2 --- /dev/null +++ b/MatchServer/Storage/MatchingDb.cs @@ -0,0 +1,22 @@ +using SharedProject.models; + +namespace MatchServer.Storage; + +public class MatchingDb +{ + public Dictionary> MatchingDictionary; + + public object DbLock = new(); + + static MatchingDb() + { + } + + private MatchingDb() + { + MatchingDictionary = new Dictionary>(); + } + + public static MatchingDb GetInstance { get; } = new MatchingDb(); + +} \ No newline at end of file diff --git a/MatchServer/appsettings.Development.json b/MatchServer/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/MatchServer/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/MatchServer/appsettings.json b/MatchServer/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/MatchServer/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/SharedProject/models/OnlineMatchingData.cs b/SharedProject/models/OnlineMatchingData.cs new file mode 100644 index 0000000..4bbd544 --- /dev/null +++ b/SharedProject/models/OnlineMatchingData.cs @@ -0,0 +1,44 @@ +namespace SharedProject.models; + +public class OnlineMatchingData +{ + public long MachineId { get; set; } + + public long EventId { get; set; } + + public long MatchingId { get; set; } + + public long EntryNo { get; set; } + + public string EntryStart { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + + public long Status { get; set; } = 1; + + public long CardId { get; set; } + + public string PlayerName { get; set; } = string.Empty; + + public long AvatarId { get; set; } + + public long TitleId { get; set; } + + public long ClassId { get; set; } + + public long GroupId { get; set; } + + public long TenpoId { get; set; } + + public string TenpoName { get; set; } = "1337"; + + public long PrefId { get; set; } + + public string Pref { get; set; } = "nesys"; + + public long MessageId { get; set; } + + public long MatchingTimeout { get; set; } = 99; + + public long MatchingWaitTime { get; set; } = 10; + + public long MatchingRemainingTime { get; set; } = 3; +} \ No newline at end of file diff --git a/SharedProject/models/OnlineMatchingFinishRequest.cs b/SharedProject/models/OnlineMatchingFinishRequest.cs new file mode 100644 index 0000000..7213a9a --- /dev/null +++ b/SharedProject/models/OnlineMatchingFinishRequest.cs @@ -0,0 +1,8 @@ +namespace SharedProject.models; + +public class OnlineMatchingFinishRequest +{ + public long CardId { get; set; } + + public long MatchingId { get; set; } +} \ No newline at end of file diff --git a/SharedProject/models/OnlineMatchingUpdateRequest.cs b/SharedProject/models/OnlineMatchingUpdateRequest.cs new file mode 100644 index 0000000..3a23d64 --- /dev/null +++ b/SharedProject/models/OnlineMatchingUpdateRequest.cs @@ -0,0 +1,14 @@ +namespace SharedProject.models; + +public class OnlineMatchingUpdateRequest +{ + public long Action { get; set; } + + public long EventId { get; set; } + + public long CardId { get; set; } + + public long MatchingId { get; set; } + + public long MessageId { get; set; } +} \ No newline at end of file