diff --git a/TaikoLocalServer/Controllers/Api/CardsController.cs b/TaikoLocalServer/Controllers/Api/CardsController.cs index ae98de2..3438ae4 100644 --- a/TaikoLocalServer/Controllers/Api/CardsController.cs +++ b/TaikoLocalServer/Controllers/Api/CardsController.cs @@ -1,30 +1,24 @@ -namespace TaikoLocalServer.Controllers.Api; +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Controllers.Api; [ApiController] [Route("api/[controller]")] public class CardsController : BaseController { - private readonly TaikoDbContext context; + private readonly ICardService cardService; - public CardsController(TaikoDbContext context) + public CardsController(ICardService cardService) { - this.context = context; + this.cardService = cardService; } [HttpDelete("{accessCode}")] public async Task DeleteUser(string accessCode) { - var card = await context.Cards.FindAsync(accessCode); + var result = await cardService.DeleteCard(accessCode); - if (card is null) - { - return NotFound(); - } - - context.Cards.Remove(card); - await context.SaveChangesAsync(); - - return NoContent(); + return result ? NoContent() : NotFound(); } } \ No newline at end of file diff --git a/TaikoLocalServer/Controllers/Api/DashboardController.cs b/TaikoLocalServer/Controllers/Api/DashboardController.cs index 1dddd88..e3158da 100644 --- a/TaikoLocalServer/Controllers/Api/DashboardController.cs +++ b/TaikoLocalServer/Controllers/Api/DashboardController.cs @@ -1,6 +1,7 @@ using SharedProject.Models; using SharedProject.Models.Responses; using Swan.Mapping; +using TaikoLocalServer.Services.Interfaces; namespace TaikoLocalServer.Controllers.Api; @@ -10,16 +11,18 @@ public class DashboardController : BaseController { private readonly TaikoDbContext context; - public DashboardController(TaikoDbContext context) + private readonly ICardService cardService; + + public DashboardController(TaikoDbContext context, ICardService cardService) { this.context = context; + this.cardService = cardService; } [HttpGet] - public DashboardResponse GetDashboard() + public async Task GetDashboard() { - var cards = context.Cards.AsEnumerable(); - var users = cards.Select(card => card.CopyPropertiesToNew()).ToList(); + var users = await cardService.GetUsersFromCards(); return new DashboardResponse { Users = users diff --git a/TaikoLocalServer/Controllers/Api/UserSettingsController.cs b/TaikoLocalServer/Controllers/Api/UserSettingsController.cs index 40f2b7a..f4da8a9 100644 --- a/TaikoLocalServer/Controllers/Api/UserSettingsController.cs +++ b/TaikoLocalServer/Controllers/Api/UserSettingsController.cs @@ -2,6 +2,8 @@ using SharedProject.Models; using SharedProject.Models.Responses; using SharedProject.Utils; +using TaikoLocalServer.Services; +using TaikoLocalServer.Services.Interfaces; namespace TaikoLocalServer.Controllers.Api; @@ -11,15 +13,18 @@ public class UserSettingsController : BaseController { private readonly TaikoDbContext context; - public UserSettingsController(TaikoDbContext context) + private readonly IUserDatumService userDatumService; + + public UserSettingsController(TaikoDbContext context, IUserDatumService userDatumService) { this.context = context; + this.userDatumService = userDatumService; } [HttpGet] public async Task> GetUserSetting(uint baid) { - var user = await context.UserData.FirstOrDefaultAsync(datum => datum.Baid == baid); + var user = await userDatumService.GetFirstUserDatumOrNull(baid); if (user is null) { @@ -46,7 +51,7 @@ public class UserSettingsController : BaseController [HttpPost] public async Task SaveUserSetting(uint baid, UserSetting userSetting) { - var user = await context.UserData.FindAsync(baid); + var user = await userDatumService.GetFirstUserDatumOrNull(baid); if (user is null) { @@ -65,8 +70,7 @@ public class UserSettingsController : BaseController user.Title = userSetting.Title; user.TitlePlateId = userSetting.TitlePlateId; - context.Update(user); - await context.SaveChangesAsync(); + await userDatumService.UpdateUserDatum(user); return NoContent(); } diff --git a/TaikoLocalServer/Controllers/Game/BaidController.cs b/TaikoLocalServer/Controllers/Game/BaidController.cs index 7d53232..b63d5b9 100644 --- a/TaikoLocalServer/Controllers/Game/BaidController.cs +++ b/TaikoLocalServer/Controllers/Game/BaidController.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using TaikoLocalServer.Services.Interfaces; namespace TaikoLocalServer.Controllers.Game; @@ -6,24 +7,35 @@ namespace TaikoLocalServer.Controllers.Game; [Route("/v12r03/chassis/baidcheck.php")] public class BaidController : BaseController { - private readonly TaikoDbContext context; + private readonly IUserDatumService userDatumService; - public BaidController(TaikoDbContext context) + private readonly ICardService cardService; + + private readonly ISongBestDatumService songBestDatumService; + + private readonly IDanScoreDatumService danScoreDatumService; + + public BaidController(IUserDatumService userDatumService, ICardService cardService, + ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService) { - this.context = context; + this.userDatumService = userDatumService; + this.cardService = cardService; + this.songBestDatumService = songBestDatumService; + this.danScoreDatumService = danScoreDatumService; } [HttpPost] [Produces("application/protobuf")] - public IActionResult GetBaid([FromBody] BAIDRequest request) + public async Task GetBaid([FromBody] BAIDRequest request) { Logger.LogInformation("Baid request: {Request}", request.Stringify()); BAIDResponse response; - if (!context.Cards.Any(card => card.AccessCode == request.AccessCode)) + var card = await cardService.GetCardByAccessCode(request.AccessCode); + if (card is null) { - Logger.LogInformation("New user from access code {AccessCode}", request.AccessCode); - var newId = context.Cards.Any() ? context.Cards.Max(card => card.Baid) + 1 : 1; + Logger.LogInformation("New user with access code {AccessCode}", request.AccessCode); + var newId = cardService.GetNextBaid(); response = new BAIDResponse { @@ -43,15 +55,11 @@ public class BaidController : BaseController return Ok(response); } - var baid = context.Cards.First(card => card.AccessCode == request.AccessCode).Baid; + var baid = card.Baid; - var userData = new UserDatum(); - if (context.UserData.Any(datum => datum.Baid == baid)) - { - userData = context.UserData.First(datum => datum.Baid == baid); - } + var userData = await userDatumService.GetFirstUserDatumOrDefault(baid); - var songBestData = context.SongBestData.Where(datum => datum.Baid == baid).ToList(); + var songBestData = await songBestDatumService.GetAllSongBestData(baid); var achievementDisplayDifficulty = userData.AchievementDisplayDifficulty; if (userData.AchievementDisplayDifficulty == Difficulty.None) @@ -102,16 +110,13 @@ public class BaidController : BaseController var costumeFlag = new byte[10]; Array.Fill(costumeFlag, byte.MaxValue); - var danData = context.DanScoreData - .Where(datum => datum.Baid == baid) - .Include(datum => datum.DanStageScoreData) - .ToList(); + var danData = await danScoreDatumService.GetDanScoreDatumByBaid(baid); + var maxDan = danData.Where(datum => datum.ClearState != DanClearState.NotClear) .Select(datum => datum.DanId) .DefaultIfEmpty() .Max(); var gotDanFlagArray = FlagCalculator.ComputeGotDanFlags(danData); - Logger.LogInformation("Got dan array {Array}", gotDanFlagArray.Stringify()); response = new BAIDResponse { diff --git a/TaikoLocalServer/Controllers/Game/CrownsDataController.cs b/TaikoLocalServer/Controllers/Game/CrownsDataController.cs index a041e76..41cc3c5 100644 --- a/TaikoLocalServer/Controllers/Game/CrownsDataController.cs +++ b/TaikoLocalServer/Controllers/Game/CrownsDataController.cs @@ -1,23 +1,25 @@ -namespace TaikoLocalServer.Controllers.Game; +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Controllers.Game; [Route("/v12r03/chassis/crownsdata.php")] [ApiController] public class CrownsDataController : BaseController { - private readonly TaikoDbContext context; + private readonly ISongBestDatumService songBestDatumService; - public CrownsDataController(TaikoDbContext context) + public CrownsDataController(ISongBestDatumService songBestDatumService) { - this.context = context; + this.songBestDatumService = songBestDatumService; } [HttpPost] [Produces("application/protobuf")] - public IActionResult CrownsData([FromBody] CrownsDataRequest request) + public async Task CrownsData([FromBody] CrownsDataRequest request) { Logger.LogInformation("CrownsData request : {Request}", request.Stringify()); - var songBestData = context.SongBestData.Where(datum => datum.Baid == request.Baid).ToList(); + var songBestData = await songBestDatumService.GetAllSongBestData(request.Baid); var crown = new ushort[Constants.CROWN_FLAG_ARRAY_SIZE]; var dondafulCrown = new byte[Constants.DONDAFUL_CROWN_FLAG_ARRAY_SIZE]; diff --git a/TaikoLocalServer/Controllers/Game/GetDanScoreController.cs b/TaikoLocalServer/Controllers/Game/GetDanScoreController.cs index ef3e044..503ea49 100644 --- a/TaikoLocalServer/Controllers/Game/GetDanScoreController.cs +++ b/TaikoLocalServer/Controllers/Game/GetDanScoreController.cs @@ -1,19 +1,21 @@ -namespace TaikoLocalServer.Controllers.Game; +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Controllers.Game; [Route("/v12r03/chassis/getdanscore.php")] [ApiController] public class GetDanScoreController : BaseController { - private readonly TaikoDbContext context; + private readonly IDanScoreDatumService danScoreDatumService; - public GetDanScoreController(TaikoDbContext context) + public GetDanScoreController(IDanScoreDatumService danScoreDatumService) { - this.context = context; + this.danScoreDatumService = danScoreDatumService; } [HttpPost] [Produces("application/protobuf")] - public IActionResult GetDanScore([FromBody] GetDanScoreRequest request) + public async Task GetDanScore([FromBody] GetDanScoreRequest request) { Logger.LogInformation("GetDanScore request : {Request}", request.Stringify()); @@ -22,10 +24,7 @@ public class GetDanScoreController : BaseController Result = 1 }; - var danScoreData = context.DanScoreData - .Where(datum => datum.Baid == request.Baid) - .Include(datum => datum.DanStageScoreData) - .ToList(); + var danScoreData = await danScoreDatumService.GetDanScoreDatumByBaid(request.Baid); foreach (var danId in request.DanIds) { diff --git a/TaikoLocalServer/Controllers/Game/GetScoreRankController.cs b/TaikoLocalServer/Controllers/Game/GetScoreRankController.cs index 3110c24..6d83c0d 100644 --- a/TaikoLocalServer/Controllers/Game/GetScoreRankController.cs +++ b/TaikoLocalServer/Controllers/Game/GetScoreRankController.cs @@ -1,25 +1,27 @@ -namespace TaikoLocalServer.Controllers.Game; +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Controllers.Game; [Route("/v12r03/chassis/getscorerank.php")] [ApiController] public class GetScoreRankController : BaseController { - private readonly TaikoDbContext context; + private readonly ISongBestDatumService songBestDatumService; - public GetScoreRankController(TaikoDbContext context) + public GetScoreRankController(ISongBestDatumService songBestDatumService) { - this.context = context; + this.songBestDatumService = songBestDatumService; } [HttpPost] [Produces("application/protobuf")] - public IActionResult GetScoreRank([FromBody] GetScoreRankRequest request) + public async Task GetScoreRank([FromBody] GetScoreRankRequest request) { Logger.LogInformation("GetScoreRank request : {Request}", request.Stringify()); var kiwamiScores = new byte[Constants.KIWAMI_SCORE_RANK_ARRAY_SIZE]; var miyabiScores = new ushort[Constants.MIYABI_CORE_RANK_ARRAY_SIZE]; var ikiScores = new ushort[Constants.IKI_CORE_RANK_ARRAY_SIZE]; - var songBestData = context.SongBestData.Where(datum => datum.Baid == request.Baid).ToList(); + var songBestData = await songBestDatumService.GetAllSongBestData(request.Baid); for (var songId = 0; songId < Constants.MUSIC_ID_MAX; songId++) { diff --git a/TaikoLocalServer/Controllers/Game/InitialDataCheckController.cs b/TaikoLocalServer/Controllers/Game/InitialDataCheckController.cs index 75a5392..1693e5c 100644 --- a/TaikoLocalServer/Controllers/Game/InitialDataCheckController.cs +++ b/TaikoLocalServer/Controllers/Game/InitialDataCheckController.cs @@ -40,6 +40,7 @@ public class InitialDataCheckController : BaseController { - private readonly TaikoDbContext context; + private readonly IUserDatumService userDatumService; + + private readonly ICardService cardService; - public MyDonEntryController(TaikoDbContext context) + public MyDonEntryController(IUserDatumService userDatumService, ICardService cardService) { - this.context = context; + this.userDatumService = userDatumService; + this.cardService = cardService; } [HttpPost] [Produces("application/protobuf")] - public IActionResult GetMyDonEntry([FromBody] MydonEntryRequest request) + public async Task GetMyDonEntry([FromBody] MydonEntryRequest request) { Logger.LogInformation("MyDonEntry request : {Request}", request.Stringify()); - var newId = context.Cards.Any() ? context.Cards.Max(card => card.Baid) + 1 : 1; - context.Cards.Add(new Card + var newId = cardService.GetNextBaid(); + await cardService.AddCard(new Card { AccessCode = request.AccessCode, Baid = newId }); - - context.UserData.Add(new UserDatum + + var newUser = new UserDatum { Baid = newId, MyDonName = request.MydonName, @@ -35,9 +41,10 @@ public class MyDonEntryController : BaseController ColorBody = 1, ColorLimb = 3, FavoriteSongsArray = "{}" - }); - context.SaveChanges(); - + }; + + await userDatumService.InsertUserDatum(newUser); + var response = new MydonEntryResponse { Result = 1, diff --git a/TaikoLocalServer/Controllers/Game/PlayResultController.cs b/TaikoLocalServer/Controllers/Game/PlayResultController.cs index 880ae83..31f01ff 100644 --- a/TaikoLocalServer/Controllers/Game/PlayResultController.cs +++ b/TaikoLocalServer/Controllers/Game/PlayResultController.cs @@ -1,23 +1,37 @@ using System.Buffers.Binary; using System.Globalization; using System.Text.Json; +using TaikoLocalServer.Services.Interfaces; +using Throw; namespace TaikoLocalServer.Controllers.Game; +using StageData = PlayResultDataRequest.StageData; + [Route("/v12r03/chassis/playresult.php")] [ApiController] public class PlayResultController : BaseController { - private readonly TaikoDbContext context; + private readonly IUserDatumService userDatumService; - public PlayResultController(TaikoDbContext context) + private readonly ISongPlayDatumService songPlayDatumService; + + private readonly ISongBestDatumService songBestDatumService; + + private readonly IDanScoreDatumService danScoreDatumService; + + public PlayResultController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService, + ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService) { - this.context = context; + this.userDatumService = userDatumService; + this.songPlayDatumService = songPlayDatumService; + this.songBestDatumService = songBestDatumService; + this.danScoreDatumService = danScoreDatumService; } [HttpPost] [Produces("application/protobuf")] - public IActionResult UploadPlayResult([FromBody] PlayResultRequest request) + public async Task UploadPlayResult([FromBody] PlayResultRequest request) { Logger.LogInformation("PlayResult request : {Request}", request.Stringify()); var decompressed = GZipBytesUtil.DecompressGZipBytes(request.PlayresultData); @@ -29,88 +43,75 @@ public class PlayResultController : BaseController var response = new PlayResultResponse { Result = 1 - }; - - var lastPlayDatetime = DateTime.ParseExact(playResultData.PlayDatetime, Constants.DATE_TIME_FORMAT, CultureInfo.InvariantCulture); - - UpdateUserData(request, playResultData, lastPlayDatetime); + }; + + var lastPlayDatetime = DateTime.ParseExact(playResultData.PlayDatetime, Constants.DATE_TIME_FORMAT, + CultureInfo.InvariantCulture); + + await UpdateUserData(request, playResultData, lastPlayDatetime); + var playMode = (PlayMode)playResultData.PlayMode; - + if (playMode == PlayMode.DanMode) { - UpdateDanPlayData(request, playResultData); - context.SaveChanges(); + await UpdateDanPlayData(request, playResultData); return Ok(response); } - - var bestData = context.SongBestData.Where(datum => datum.Baid == request.BaidConf).ToList(); + + var bestData = await songBestDatumService.GetAllSongBestData(request.BaidConf); for (var songNumber = 0; songNumber < playResultData.AryStageInfoes.Count; songNumber++) { var stageData = playResultData.AryStageInfoes[songNumber]; - - UpdateBestData(request, stageData, bestData); - UpdatePlayData(request, songNumber, stageData, lastPlayDatetime); + await UpdateBestData(request, stageData, bestData); + + await UpdatePlayData(request, songNumber, stageData, lastPlayDatetime); } - - context.SaveChanges(); + return Ok(response); } - private void UpdateDanPlayData(PlayResultRequest request, PlayResultDataRequest playResultDataRequest) + private async Task UpdateDanPlayData(PlayResultRequest request, PlayResultDataRequest playResultDataRequest) { if (playResultDataRequest.IsNotRecordedDan) { Logger.LogInformation("Dan score will not be saved!"); return; } - var danScoreDataQuery = context.DanScoreData - .Where(datum => datum.Baid == request.BaidConf && - datum.DanId == playResultDataRequest.DanId) - .Include(datum => datum.DanStageScoreData); - var danScoreData = new DanScoreDatum - { - Baid = request.BaidConf, - DanId = playResultDataRequest.DanId - }; - var insert = true; - if (danScoreDataQuery.Any()) - { - danScoreData = danScoreDataQuery.First(); - insert = false; - } - danScoreData.ClearState = (DanClearState)Math.Max(playResultDataRequest.DanResult, (uint)danScoreData.ClearState); - danScoreData.ArrivalSongCount = Math.Max((uint)playResultDataRequest.AryStageInfoes.Count, danScoreData.ArrivalSongCount); + + var danScoreData = + await danScoreDatumService.GetSingleDanScoreDatum(request.BaidConf, playResultDataRequest.DanId) ?? + new DanScoreDatum + { + Baid = request.BaidConf, + DanId = playResultDataRequest.DanId + }; + danScoreData.ClearState = + (DanClearState)Math.Max(playResultDataRequest.DanResult, (uint)danScoreData.ClearState); + danScoreData.ArrivalSongCount = + Math.Max((uint)playResultDataRequest.AryStageInfoes.Count, danScoreData.ArrivalSongCount); danScoreData.ComboCountTotal = Math.Max(playResultDataRequest.ComboCntTotal, danScoreData.ComboCountTotal); danScoreData.SoulGaugeTotal = Math.Max(playResultDataRequest.SoulGaugeTotal, danScoreData.SoulGaugeTotal); UpdateDanStageData(playResultDataRequest, danScoreData); - if (insert) - { - context.DanScoreData.Add(danScoreData); - return; - } - context.DanScoreData.Update(danScoreData); + await danScoreDatumService.InsertOrUpdateDanScoreDatum(danScoreData); } + private void UpdateDanStageData(PlayResultDataRequest playResultDataRequest, DanScoreDatum danScoreData) { - for (var songNumber = 0; songNumber < playResultDataRequest.AryStageInfoes.Count; songNumber++) + for (var i = 0; i < playResultDataRequest.AryStageInfoes.Count; i++) { - var stageData = playResultDataRequest.AryStageInfoes[songNumber]; - var add = true; + var stageData = playResultDataRequest.AryStageInfoes[i]; - var danStageData = new DanStageScoreDatum - { - Baid = danScoreData.Baid, - DanId = danScoreData.DanId, - SongNumber = (uint)songNumber - }; - if (danScoreData.DanStageScoreData.Any(datum => datum.SongNumber == songNumber)) - { - danStageData = danScoreData.DanStageScoreData.First(datum => datum.SongNumber == songNumber); - add = false; - } + var songNumber = i; + var danStageData = danScoreData.DanStageScoreData.FirstOrDefault(datum => datum.SongNumber == songNumber, + new DanStageScoreDatum + { + Baid = danScoreData.Baid, + DanId = danScoreData.DanId, + SongNumber = (uint)songNumber + }); danStageData.HighScore = Math.Max(danStageData.HighScore, stageData.PlayScore); danStageData.ComboCount = Math.Max(danStageData.ComboCount, stageData.ComboCnt); @@ -120,19 +121,18 @@ public class PlayResultController : BaseController danStageData.OkCount = Math.Min(danStageData.OkCount, stageData.OkCnt); danStageData.BadCount = Math.Min(danStageData.BadCount, stageData.NgCnt); - if (add) + var index = danScoreData.DanStageScoreData.IndexOf(danStageData); + if (index == -1) { - context.DanStageScoreData.Add(danStageData); - continue; + danScoreData.DanStageScoreData.Add(danStageData); } - - context.DanStageScoreData.Update(danStageData); } } - private void UpdatePlayData(PlayResultRequest request, int songNumber, PlayResultDataRequest.StageData stageData, DateTime lastPlayDatetime) + private async Task UpdatePlayData(PlayResultRequest request, int songNumber, StageData stageData, + DateTime lastPlayDatetime) { - var playData = new SongPlayDatum + var songPlayDatum = new SongPlayDatum { Baid = request.BaidConf, SongNumber = (uint)songNumber, @@ -150,18 +150,15 @@ public class PlayResultController : BaseController PlayTime = lastPlayDatetime, Difficulty = (Difficulty)stageData.Level }; - context.SongPlayData.Add(playData); + await songPlayDatumService.AddSongPlayDatum(songPlayDatum); } - private void UpdateUserData(PlayResultRequest request, PlayResultDataRequest playResultData, DateTime lastPlayDatetime) + + private async Task UpdateUserData(PlayResultRequest request, PlayResultDataRequest playResultData, + DateTime lastPlayDatetime) { - var userdata = new UserDatum - { - Baid = request.BaidConf - }; - if (context.UserData.Any(datum => datum.Baid == request.BaidConf)) - { - userdata = context.UserData.First(datum => datum.Baid == request.BaidConf); - } + var userdata = await userDatumService.GetFirstUserDatumOrNull(request.BaidConf); + + userdata.ThrowIfNull(); userdata.Title = playResultData.Title; userdata.TitlePlateId = playResultData.TitleplateId; @@ -184,49 +181,38 @@ public class PlayResultController : BaseController userdata.LastPlayDatetime = lastPlayDatetime; userdata.LastPlayMode = playResultData.PlayMode; - context.UserData.Update(userdata); + await userDatumService.UpdateUserDatum(userdata); } - private void UpdateBestData(PlayResultRequest request, PlayResultDataRequest.StageData stageData, IEnumerable bestData) + private async Task UpdateBestData(PlayResultRequest request, StageData stageData, + IEnumerable bestData) { - var insert = false; - var data = stageData; var bestDatum = bestData - .FirstOrDefault(datum => datum.SongId == data.SongNo && - datum.Difficulty == (Difficulty)data.Level); + .FirstOrDefault(datum => datum.SongId == stageData.SongNo && + datum.Difficulty == (Difficulty)stageData.Level, + new SongBestDatum + { + Baid = request.BaidConf, + SongId = stageData.SongNo, + Difficulty = (Difficulty)stageData.Level + }); // Determine whether it is dondaful crown as this is not reflected by play result var crown = PlayResultToCrown(stageData); - if (bestDatum is null) - { - insert = true; - bestDatum = new SongBestDatum - { - Baid = request.BaidConf, - SongId = stageData.SongNo, - Difficulty = (Difficulty)stageData.Level - }; - } - bestDatum.UpdateBestData(crown, stageData.ScoreRank, stageData.PlayScore, stageData.ScoreRate); - if (insert) - { - context.SongBestData.Add(bestDatum); - } - else - { - context.SongBestData.Update(bestDatum); - } + await songBestDatumService.UpdateOrInsertSongBestDatum(bestDatum); } - private static CrownType PlayResultToCrown(PlayResultDataRequest.StageData stageData) + + private static CrownType PlayResultToCrown(StageData stageData) { var crown = (CrownType)stageData.PlayResult; if (crown == CrownType.Gold && stageData.OkCnt == 0) { crown = CrownType.Dondaful; } + return crown; } } \ No newline at end of file diff --git a/TaikoLocalServer/Controllers/Game/SelfBestController.cs b/TaikoLocalServer/Controllers/Game/SelfBestController.cs index 8b7e74d..6c514d8 100644 --- a/TaikoLocalServer/Controllers/Game/SelfBestController.cs +++ b/TaikoLocalServer/Controllers/Game/SelfBestController.cs @@ -1,4 +1,5 @@ -using Throw; +using TaikoLocalServer.Services.Interfaces; +using Throw; namespace TaikoLocalServer.Controllers.Game; @@ -6,16 +7,16 @@ namespace TaikoLocalServer.Controllers.Game; [ApiController] public class SelfBestController : BaseController { - private readonly TaikoDbContext context; + private readonly ISongBestDatumService songBestDatumService; - public SelfBestController(TaikoDbContext context) + public SelfBestController(ISongBestDatumService songBestDatumService) { - this.context = context; + this.songBestDatumService = songBestDatumService; } [HttpPost] [Produces("application/protobuf")] - public IActionResult SelfBest([FromBody] SelfBestRequest request) + public async Task SelfBest([FromBody] SelfBestRequest request) { Logger.LogInformation("SelfBest request : {Request}", request.Stringify()); @@ -30,10 +31,10 @@ public class SelfBestController : BaseController var requestDifficulty = (Difficulty)request.Level; requestDifficulty.Throw().IfOutOfRange(); - var playerBestData = context.SongBestData - .Where(datum => datum.Baid == request.Baid && - (datum.Difficulty == requestDifficulty || - (datum.Difficulty == Difficulty.UraOni && requestDifficulty == Difficulty.Oni))) + var playerBestData = await songBestDatumService.GetAllSongBestData(request.Baid); + playerBestData = playerBestData + .Where(datum => datum.Difficulty == requestDifficulty || + (datum.Difficulty == Difficulty.UraOni && requestDifficulty == Difficulty.Oni)) .ToList(); foreach (var songNo in request.ArySongNoes) { diff --git a/TaikoLocalServer/Controllers/Game/UserDataController.cs b/TaikoLocalServer/Controllers/Game/UserDataController.cs index 515c552..e02f074 100644 --- a/TaikoLocalServer/Controllers/Game/UserDataController.cs +++ b/TaikoLocalServer/Controllers/Game/UserDataController.cs @@ -1,6 +1,7 @@ using System.Buffers.Binary; using System.Collections; using System.Text.Json; +using TaikoLocalServer.Services.Interfaces; using Throw; namespace TaikoLocalServer.Controllers.Game; @@ -9,16 +10,19 @@ namespace TaikoLocalServer.Controllers.Game; [ApiController] public class UserDataController : BaseController { - private readonly TaikoDbContext context; + private readonly IUserDatumService userDatumService; + + private readonly ISongPlayDatumService songPlayDatumService; - public UserDataController(TaikoDbContext context) + public UserDataController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService) { - this.context = context; + this.userDatumService = userDatumService; + this.songPlayDatumService = songPlayDatumService; } [HttpPost] [Produces("application/protobuf")] - public IActionResult GetUserData([FromBody] UserDataRequest request) + public async Task GetUserData([FromBody] UserDataRequest request) { Logger.LogInformation("UserData request : {Request}", request.Stringify()); @@ -43,8 +47,7 @@ public class UserDataController : BaseController var toneArray = new byte[16]; Array.Fill(toneArray, byte.MaxValue); - var recentSongs = context.SongPlayData - .Where(datum => datum.Baid == request.Baid) + var recentSongs = (await songPlayDatumService.GetSongPlayDatumByBaid(request.Baid)) .AsEnumerable() .OrderByDescending(datum => datum.PlayTime) .ThenByDescending(datum => datum.SongNumber) @@ -64,11 +67,7 @@ public class UserDataController : BaseController recentSongs = recentSet.ToArray(); - var userData = new UserDatum(); - if (context.UserData.Any(datum => datum.Baid == request.Baid)) - { - userData = context.UserData.First(datum => datum.Baid == request.Baid); - } + var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid); var favoriteSongs = Array.Empty(); try diff --git a/TaikoLocalServer/Program.cs b/TaikoLocalServer/Program.cs index e800843..dd6c5b9 100644 --- a/TaikoLocalServer/Program.cs +++ b/TaikoLocalServer/Program.cs @@ -2,6 +2,9 @@ using System.Security.Authentication; using Microsoft.AspNetCore.HttpLogging; using Microsoft.AspNetCore.HttpOverrides; using TaikoLocalServer.Middlewares; +using TaikoLocalServer.Services; +using TaikoLocalServer.Services.Extentions; +using TaikoLocalServer.Services.Interfaces; using TaikoLocalServer.Settings; var builder = WebApplication.CreateBuilder(args); @@ -44,6 +47,7 @@ builder.Services.AddCors(options => .AllowAnyHeader(); }); }); +builder.Services.AddTaikoDbServices(); var app = builder.Build(); diff --git a/TaikoLocalServer/Services/CardService.cs b/TaikoLocalServer/Services/CardService.cs new file mode 100644 index 0000000..cd6006b --- /dev/null +++ b/TaikoLocalServer/Services/CardService.cs @@ -0,0 +1,51 @@ +using SharedProject.Models; +using Swan.Mapping; +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Services; + +public class CardService : ICardService +{ + private readonly TaikoDbContext context; + + public CardService(TaikoDbContext context) + { + this.context = context; + } + + public async Task GetCardByAccessCode(string accessCode) + { + return await context.Cards.FindAsync(accessCode); + } + + public uint GetNextBaid() + { + return context.Cards.Any() ? context.Cards.Max(card => card.Baid) + 1 : 1; + } + + public async Task> GetUsersFromCards() + { + return await context.Cards.Select(card => card.CopyPropertiesToNew(null)).ToListAsync(); + } + + public async Task AddCard(Card card) + { + context.Add(card); + await context.SaveChangesAsync(); + } + + public async Task DeleteCard(string accessCode) + { + var card = await context.Cards.FindAsync(accessCode); + + if (card is null) + { + return false; + } + + context.Cards.Remove(card); + await context.SaveChangesAsync(); + + return true; + } +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/DanScoreDatumService.cs b/TaikoLocalServer/Services/DanScoreDatumService.cs new file mode 100644 index 0000000..01591d8 --- /dev/null +++ b/TaikoLocalServer/Services/DanScoreDatumService.cs @@ -0,0 +1,41 @@ +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Services; + +public class DanScoreDatumService : IDanScoreDatumService +{ + private readonly TaikoDbContext context; + + public DanScoreDatumService(TaikoDbContext context) + { + this.context = context; + } + + public async Task> GetDanScoreDatumByBaid(uint baid) + { + return await context.DanScoreData.Where(datum => datum.Baid == baid) + .Include(datum => datum.DanStageScoreData) + .ToListAsync(); + } + + public async Task GetSingleDanScoreDatum(uint baid, uint danId) + { + return await context.DanScoreData.Include(datum => datum.DanStageScoreData) + .FirstOrDefaultAsync(datum => datum.Baid == baid && + datum.DanId == danId); + } + + public async Task InsertOrUpdateDanScoreDatum(DanScoreDatum datum) + { + var existing = await context.DanScoreData.FindAsync(datum.Baid, datum.DanId); + if (existing is null) + { + await context.DanScoreData.AddAsync(datum); + await context.SaveChangesAsync(); + return; + } + + context.DanScoreData.Update(datum); + await context.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/Extentions/ServiceExtensions.cs b/TaikoLocalServer/Services/Extentions/ServiceExtensions.cs new file mode 100644 index 0000000..d7be170 --- /dev/null +++ b/TaikoLocalServer/Services/Extentions/ServiceExtensions.cs @@ -0,0 +1,17 @@ +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Services.Extentions; + +public static class ServiceExtensions +{ + public static IServiceCollection AddTaikoDbServices(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/Interfaces/ICardService.cs b/TaikoLocalServer/Services/Interfaces/ICardService.cs new file mode 100644 index 0000000..89b76b5 --- /dev/null +++ b/TaikoLocalServer/Services/Interfaces/ICardService.cs @@ -0,0 +1,16 @@ +using SharedProject.Models; + +namespace TaikoLocalServer.Services.Interfaces; + +public interface ICardService +{ + public Task GetCardByAccessCode(string accessCode); + + public uint GetNextBaid(); + + public Task> GetUsersFromCards(); + + public Task AddCard(Card card); + + public Task DeleteCard(string accessCode); +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/Interfaces/IDanScoreDatumService.cs b/TaikoLocalServer/Services/Interfaces/IDanScoreDatumService.cs new file mode 100644 index 0000000..745df94 --- /dev/null +++ b/TaikoLocalServer/Services/Interfaces/IDanScoreDatumService.cs @@ -0,0 +1,10 @@ +namespace TaikoLocalServer.Services.Interfaces; + +public interface IDanScoreDatumService +{ + public Task> GetDanScoreDatumByBaid(uint baid); + + public Task GetSingleDanScoreDatum(uint baid, uint danId); + + public Task InsertOrUpdateDanScoreDatum(DanScoreDatum datum); +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/Interfaces/ISongBestDatumService.cs b/TaikoLocalServer/Services/Interfaces/ISongBestDatumService.cs new file mode 100644 index 0000000..d9c4dac --- /dev/null +++ b/TaikoLocalServer/Services/Interfaces/ISongBestDatumService.cs @@ -0,0 +1,8 @@ +namespace TaikoLocalServer.Services.Interfaces; + +public interface ISongBestDatumService +{ + public Task> GetAllSongBestData(uint baid); + + public Task UpdateOrInsertSongBestDatum(SongBestDatum datum); +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/Interfaces/ISongPlayDatumService.cs b/TaikoLocalServer/Services/Interfaces/ISongPlayDatumService.cs new file mode 100644 index 0000000..a8cf441 --- /dev/null +++ b/TaikoLocalServer/Services/Interfaces/ISongPlayDatumService.cs @@ -0,0 +1,8 @@ +namespace TaikoLocalServer.Services.Interfaces; + +public interface ISongPlayDatumService +{ + public Task> GetSongPlayDatumByBaid(uint baid); + + public Task AddSongPlayDatum(SongPlayDatum datum); +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/Interfaces/IUserDatumService.cs b/TaikoLocalServer/Services/Interfaces/IUserDatumService.cs new file mode 100644 index 0000000..f267905 --- /dev/null +++ b/TaikoLocalServer/Services/Interfaces/IUserDatumService.cs @@ -0,0 +1,16 @@ +namespace TaikoLocalServer.Services.Interfaces; + +public interface IUserDatumService +{ + public Task GetFirstUserDatumOrNull(uint baid); + + public Task GetFirstUserDatumOrDefault(uint baid); + + public Task> GetAllUserData(); + + public Task UpdateOrInsertUserDatum(UserDatum userDatum); + + public Task InsertUserDatum(UserDatum userDatum); + + public Task UpdateUserDatum(UserDatum userDatum); +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/SongBestDatumService.cs b/TaikoLocalServer/Services/SongBestDatumService.cs new file mode 100644 index 0000000..05178d9 --- /dev/null +++ b/TaikoLocalServer/Services/SongBestDatumService.cs @@ -0,0 +1,35 @@ +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Services; + +public class SongBestDatumService : ISongBestDatumService +{ + private readonly TaikoDbContext context; + + public SongBestDatumService(TaikoDbContext context) + { + this.context = context; + } + + public async Task> GetAllSongBestData(uint baid) + { + return await context.SongBestData.Where(datum => datum.Baid == baid).ToListAsync(); + } + + public async Task UpdateOrInsertSongBestDatum(SongBestDatum datum) + { + var existing = await context.SongBestData.AnyAsync( + bestDatum => bestDatum.Baid == datum.Baid && + bestDatum.Difficulty == datum.Difficulty && + bestDatum.SongId == datum.SongId); + if (existing) + { + context.SongBestData.Update(datum); + await context.SaveChangesAsync(); + return; + } + + await context.SongBestData.AddAsync(datum); + await context.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/SongPlayDatumService.cs b/TaikoLocalServer/Services/SongPlayDatumService.cs new file mode 100644 index 0000000..a93eb41 --- /dev/null +++ b/TaikoLocalServer/Services/SongPlayDatumService.cs @@ -0,0 +1,24 @@ +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Services; + +class SongPlayDatumService : ISongPlayDatumService +{ + private readonly TaikoDbContext context; + + public SongPlayDatumService(TaikoDbContext context) + { + this.context = context; + } + + public async Task> GetSongPlayDatumByBaid(uint baid) + { + return await context.SongPlayData.Where(datum => datum.Baid == baid).ToListAsync(); + } + + public async Task AddSongPlayDatum(SongPlayDatum datum) + { + await context.SongPlayData.AddAsync(datum); + await context.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/TaikoLocalServer/Services/UserDatumService.cs b/TaikoLocalServer/Services/UserDatumService.cs new file mode 100644 index 0000000..03526ca --- /dev/null +++ b/TaikoLocalServer/Services/UserDatumService.cs @@ -0,0 +1,53 @@ +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Services; + +public class UserDatumService : IUserDatumService +{ + private readonly TaikoDbContext context; + + public UserDatumService(TaikoDbContext context) + { + this.context = context; + } + + public async Task GetFirstUserDatumOrNull(uint baid) + { + return await context.UserData.FindAsync(baid); + } + + public async Task GetFirstUserDatumOrDefault(uint baid) + { + return await context.UserData.FindAsync(baid) ?? new UserDatum(); + } + + public async Task> GetAllUserData() + { + return await context.UserData.ToListAsync(); + } + + public async Task UpdateOrInsertUserDatum(UserDatum userDatum) + { + if (await context.UserData.AnyAsync(datum => datum.Baid == userDatum.Baid)) + { + context.UserData.Add(userDatum); + await context.SaveChangesAsync(); + return; + } + + context.Update(userDatum); + await context.SaveChangesAsync(); + } + + public async Task InsertUserDatum(UserDatum userDatum) + { + context.UserData.Add(userDatum); + await context.SaveChangesAsync(); + } + + public async Task UpdateUserDatum(UserDatum userDatum) + { + context.Update(userDatum); + await context.SaveChangesAsync(); + } +} \ No newline at end of file