From 69d39da2687e8cc68125af17a7ecf00c9870a928 Mon Sep 17 00:00:00 2001 From: Simon <63975668+Simyon264@users.noreply.github.com> Date: Thu, 2 May 2024 14:31:18 +0200 Subject: [PATCH] Move search from ReplayParser to ReplayController It does not even parse replays what was i doing --- Server/Api/ReplayController.cs | 116 ++++++++++++++++++++++++++++++++- Server/ReplayParser.cs | 110 ------------------------------- 2 files changed, 115 insertions(+), 111 deletions(-) diff --git a/Server/Api/ReplayController.cs b/Server/Api/ReplayController.cs index 39af901..f761fe8 100644 --- a/Server/Api/ReplayController.cs +++ b/Server/Api/ReplayController.cs @@ -3,8 +3,12 @@ using Microsoft.EntityFrameworkCore; using Shared; using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.Extensions.Caching.Memory; +using Serilog; using Server.Helpers; +using Shared.Models; namespace Server.Api; @@ -99,7 +103,7 @@ public async Task SearchReplays( return BadRequest("The page number cannot be negative."); } - var found = ReplayParser.SearchReplays(searchMode, query, _context, page, Constants.ReplaysPerPage, _cache); + var found = SearchReplays(searchMode, query, page, Constants.ReplaysPerPage); var pageCount = Paginator.GetPageCount(found.Item2, Constants.ReplaysPerPage); @@ -153,4 +157,114 @@ public async Task GetReplay(int id) return Ok(replay); } + + /// + /// Searches a list of replays for a specific query. + /// + /// The search mode. + /// The search query. + /// The list of replays to search. + /// + /// A list of replays that match the search query. + /// + /// + /// Thrown when the search mode is not implemented. + /// + public (List, int, bool) SearchReplays(SearchMode mode, string query, int page, int pageSize) + { + var cacheKey = $"{mode}-{query}-{pageSize}"; + if (_cache.TryGetValue(cacheKey, out List<(List, int)> cachedResult)) + { + if (page < cachedResult.Count) + { + var result = cachedResult[page]; + return (result.Item1, result.Item2, true); + } + } + + var stopWatch = new Stopwatch(); + stopWatch.Start(); + var queryable = _context.Replays.AsQueryable(); + + + IIncludableQueryable? players; + IQueryable? replayIds; + switch (mode) + { + case SearchMode.Map: + queryable = queryable.Where(x => x.Map.ToLower().Contains(query.ToLower())); + break; + case SearchMode.Gamemode: + queryable = queryable.Where(x => x.Gamemode.ToLower().Contains(query.ToLower())); + break; + case SearchMode.ServerId: + queryable = queryable.Where(x => x.ServerId.ToLower().Contains(query.ToLower())); + break; + case SearchMode.Guid: + players = _context.Players + .Where(p => p.PlayerGuid.ToString().ToLower().Contains(query.ToLower())) + .Include(p => p.Replay); + replayIds = players.Select(p => p.ReplayId).Distinct(); + queryable = _context.Replays.Where(r => replayIds.Contains(r.Id)); + break; + case SearchMode.PlayerIcName: + players = _context.Players + .Where(p => p.PlayerIcName.ToLower().Contains(query.ToLower())) + .Include(p => p.Replay); + replayIds = players.Select(p => p.ReplayId).Distinct(); + queryable = _context.Replays.Where(r => replayIds.Contains(r.Id)); + break; + case SearchMode.PlayerOocName: + players = _context.Players + .Where(p => p.PlayerOocName.ToLower().Contains(query.ToLower())) + .Include(p => p.Replay); + replayIds = players.Select(p => p.ReplayId).Distinct(); + queryable = _context.Replays.Where(r => replayIds.Contains(r.Id)); + break; + case SearchMode.RoundEndText: + // ReSharper disable once EntityFramework.UnsupportedServerSideFunctionCall (its lying, this works) + queryable = queryable.Where(x => x.RoundEndTextSearchVector.Matches(query)); + break; + case SearchMode.ServerName: + queryable = queryable.Where(x => x.ServerName != null && x.ServerName.ToLower().Contains(query.ToLower())); + break; + case SearchMode.RoundId: + queryable = queryable.Where(x => x.RoundId != null && x.RoundId.ToString().Contains(query)); + break; + default: + throw new NotImplementedException(); + } + + var totalItems = queryable.Count(); + + // Get all results and store them in the cache + var allResults = queryable + .Include(r => r.RoundEndPlayers) + .OrderByDescending(r => r.Date ?? DateTime.MinValue) + .Take(Constants.SearchLimit) + .ToList(); + + var paginatedResults = new List<(List, int)>(); + for (int i = 0; i * pageSize < allResults.Count; i++) + { + var paginatedList = allResults + .Skip(i * pageSize) + .Take(pageSize) + .ToList(); + + paginatedResults.Add((paginatedList, totalItems)); + } + + _cache.Set(cacheKey, paginatedResults, TimeSpan.FromMinutes(5)); + + stopWatch.Stop(); + Log.Information("Search took " + stopWatch.ElapsedMilliseconds + "ms."); + + if (page < paginatedResults.Count) + { + return (paginatedResults[page].Item1, paginatedResults[page].Item2, false); + } + + return (new List(), 0, false); + } } diff --git a/Server/ReplayParser.cs b/Server/ReplayParser.cs index e52215b..caf723d 100644 --- a/Server/ReplayParser.cs +++ b/Server/ReplayParser.cs @@ -283,114 +283,4 @@ public static HttpClient CreateHttpClient() client.DefaultRequestHeaders.Add("User-Agent", "ReplayBrowser"); return client; } - - /// - /// Searches a list of replays for a specific query. - /// - /// The search mode. - /// The search query. - /// The list of replays to search. - /// - /// A list of replays that match the search query. - /// - /// - /// Thrown when the search mode is not implemented. - /// - public static (List, int, bool) SearchReplays(SearchMode mode, string query, ReplayDbContext context, int page, int pageSize, IMemoryCache cache) - { - var cacheKey = $"{mode}-{query}-{pageSize}"; - if (cache.TryGetValue(cacheKey, out List<(List, int)> cachedResult)) - { - if (page < cachedResult.Count) - { - var result = cachedResult[page]; - return (result.Item1, result.Item2, true); - } - } - - var stopWatch = new Stopwatch(); - stopWatch.Start(); - var queryable = context.Replays.AsQueryable(); - - - IIncludableQueryable? players; - IQueryable? replayIds; - switch (mode) - { - case SearchMode.Map: - queryable = queryable.Where(x => x.Map.ToLower().Contains(query.ToLower())); - break; - case SearchMode.Gamemode: - queryable = queryable.Where(x => x.Gamemode.ToLower().Contains(query.ToLower())); - break; - case SearchMode.ServerId: - queryable = queryable.Where(x => x.ServerId.ToLower().Contains(query.ToLower())); - break; - case SearchMode.Guid: - players = context.Players - .Where(p => p.PlayerGuid.ToString().ToLower().Contains(query.ToLower())) - .Include(p => p.Replay); - replayIds = players.Select(p => p.ReplayId).Distinct(); - queryable = context.Replays.Where(r => replayIds.Contains(r.Id)); - break; - case SearchMode.PlayerIcName: - players = context.Players - .Where(p => p.PlayerIcName.ToLower().Contains(query.ToLower())) - .Include(p => p.Replay); - replayIds = players.Select(p => p.ReplayId).Distinct(); - queryable = context.Replays.Where(r => replayIds.Contains(r.Id)); - break; - case SearchMode.PlayerOocName: - players = Context.Players - .Where(p => p.PlayerOocName.ToLower().Contains(query.ToLower())) - .Include(p => p.Replay); - replayIds = players.Select(p => p.ReplayId).Distinct(); - queryable = Context.Replays.Where(r => replayIds.Contains(r.Id)); - break; - case SearchMode.RoundEndText: - // ReSharper disable once EntityFramework.UnsupportedServerSideFunctionCall (its lying, this works) - queryable = queryable.Where(x => x.RoundEndTextSearchVector.Matches(query)); - break; - case SearchMode.ServerName: - queryable = queryable.Where(x => x.ServerName != null && x.ServerName.ToLower().Contains(query.ToLower())); - break; - case SearchMode.RoundId: - queryable = queryable.Where(x => x.RoundId != null && x.RoundId.ToString().Contains(query)); - break; - default: - throw new NotImplementedException(); - } - - var totalItems = queryable.Count(); - - // Get all results and store them in the cache - var allResults = queryable - .Include(r => r.RoundEndPlayers) - .OrderByDescending(r => r.Date ?? DateTime.MinValue) - .Take(Constants.SearchLimit) - .ToList(); - - var paginatedResults = new List<(List, int)>(); - for (int i = 0; i * pageSize < allResults.Count; i++) - { - var paginatedList = allResults - .Skip(i * pageSize) - .Take(pageSize) - .ToList(); - - paginatedResults.Add((paginatedList, totalItems)); - } - - cache.Set(cacheKey, paginatedResults, TimeSpan.FromMinutes(5)); - - stopWatch.Stop(); - Log.Information("Search took " + stopWatch.ElapsedMilliseconds + "ms."); - - if (page < paginatedResults.Count) - { - return (paginatedResults[page].Item1, paginatedResults[page].Item2, false); - } - - return (new List(), 0, false); - } }