From 1e729cf1933a49b92721e272ff84d904bc52b6de Mon Sep 17 00:00:00 2001 From: RaidMax Date: Thu, 25 Apr 2019 21:05:35 -0500 Subject: [PATCH] optimize the find client query --- Application/Application.csproj | 6 +- README.md | 2 +- SharedLibraryCore/Commands/NativeCommands.cs | 12 ++-- SharedLibraryCore/Services/ClientService.cs | 60 ++++++++++++++++---- WebfrontCore/Controllers/ClientController.cs | 13 +---- 5 files changed, 58 insertions(+), 35 deletions(-) diff --git a/Application/Application.csproj b/Application/Application.csproj index 176c3398..a107ed19 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -6,7 +6,7 @@ 2.2.2 false RaidMax.IW4MAdmin.Application - 2.2.6.5 + 2.2.7.0 RaidMax Forever None IW4MAdmin @@ -31,8 +31,8 @@ true true - 2.2.6.5 - 2.2.6.5 + 2.2.7.0 + 2.2.7.0 diff --git a/README.md b/README.md index ad44d218..82fc924b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # IW4MAdmin ### Quick Start Guide -### Version 2.2 +### Version 2.3 _______ ### About **IW4MAdmin** is an administration tool for [IW4x](https://iw4xcachep26muba.onion.link/), [Pluto T6](https://forum.plutonium.pw/category/33/plutonium-t6), ~~[Pluto IW5](https://forum.plutonium.pw/category/5/plutonium-iw5)~~, and most Call of Duty® dedicated servers. It allows complete control of your server; from changing maps, to banning players, **IW4MAdmin** monitors and records activity on your server(s). With plugin support, extending its functionality is a breeze. diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs index 80c474e7..02a85a95 100644 --- a/SharedLibraryCore/Commands/NativeCommands.cs +++ b/SharedLibraryCore/Commands/NativeCommands.cs @@ -11,6 +11,7 @@ using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using static SharedLibraryCore.Database.Models.EFClient; namespace SharedLibraryCore.Commands { @@ -619,10 +620,7 @@ namespace SharedLibraryCore.Commands return; } - IList db_players = (await (E.Owner.Manager.GetClientService() as ClientService) - .FindClientsByIdentifier(E.Data)) - .OrderByDescending(p => p.LastConnection) - .ToList(); + var db_players = (await (E.Owner.Manager.GetClientService() as ClientService).FindClientsByIdentifier(E.Data)); if (db_players.Count == 0) { @@ -632,11 +630,11 @@ namespace SharedLibraryCore.Commands foreach (var P in db_players) { - string localizedLevel = Utilities.CurrentLocalization.LocalizationIndex[$"GLOBAL_PERMISSION_{P.Level.ToString().ToUpper()}"]; // they're not going by another alias + // /*P.AliasLink.Children.FirstOrDefault(a => a.Name.ToLower().Contains(E.Data.ToLower()))?.Name*/ string msg = P.Name.ToLower().Contains(E.Data.ToLower()) ? - $"[^3{P.Name}^7] [^3@{P.ClientId}^7] - [{ Utilities.ConvertLevelToColor(P.Level, localizedLevel)}^7] - {P.IPAddressString} | last seen {Utilities.GetTimePassed(P.LastConnection)}" : - $"({P.AliasLink.Children.FirstOrDefault(a => a.Name.ToLower().Contains(E.Data.ToLower()))?.Name})->[^3{P.Name}^7] [^3@{P.ClientId}^7] - [{ Utilities.ConvertLevelToColor(P.Level, localizedLevel)}^7] - {P.IPAddressString} | last seen {Utilities.GetTimePassed(P.LastConnection)}"; + $"[^3{P.Name}^7] [^3@{P.ClientId}^7] - [{ Utilities.ConvertLevelToColor((Permission)P.LevelInt, P.Level)}^7] - {P.IPAddress} | last seen {Utilities.GetTimePassed(P.LastConnection)}" : + $"()->[^3{P.Name}^7] [^3@{P.ClientId}^7] - [{ Utilities.ConvertLevelToColor((Permission)P.LevelInt, P.Level)}^7] - {P.IPAddress} | last seen {Utilities.GetTimePassed(P.LastConnection)}"; E.Origin.Tell(msg); } } diff --git a/SharedLibraryCore/Services/ClientService.cs b/SharedLibraryCore/Services/ClientService.cs index 800dbcc5..1d926f5e 100644 --- a/SharedLibraryCore/Services/ClientService.cs +++ b/SharedLibraryCore/Services/ClientService.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using SharedLibraryCore.Database; using SharedLibraryCore.Database.Models; +using SharedLibraryCore.Dtos; using SharedLibraryCore.Objects; using System; using System.Collections.Generic; @@ -439,11 +440,11 @@ namespace SharedLibraryCore.Services } } - public async Task> FindClientsByIdentifier(string identifier) + public async Task> FindClientsByIdentifier(string identifier) { if (identifier?.Length < 3) { - return new List(); + return new List(); } identifier = identifier.ToLower(); @@ -453,24 +454,59 @@ namespace SharedLibraryCore.Services long networkId = identifier.ConvertLong(); int? ipAddress = identifier.ConvertToIP(); - var iqLinkIds = (from alias in context.Aliases - where (alias.IPAddress != null && alias.IPAddress == ipAddress) || - alias.Name.ToLower().Contains(identifier) - select alias.LinkId).Distinct(); + IQueryable iqLinkIds = context.Aliases.Where(_alias => _alias.Active); - var linkIds = await iqLinkIds.ToListAsync(); + // we want to query for the IP ADdress + if (ipAddress != null) + { + iqLinkIds = iqLinkIds.Where(_alias => _alias.IPAddress == ipAddress); + } + // want to find them by name (wildcard) + // todo maybe not make it start with wildcard? + else + { + iqLinkIds = iqLinkIds.Where(_alias => EF.Functions.Like(_alias.Name, $"%{identifier}%")); + } + + var linkIds = await iqLinkIds + .Select(_alias => _alias.LinkId) + .ToListAsync(); + + // get all the clients that match the alias link or the network id var iqClients = context.Clients - .Where(c => linkIds.Contains(c.AliasLinkId) || - networkId == c.NetworkId) - .Include(c => c.CurrentAlias) - .Include(c => c.AliasLink.Children); + .Where(_client => _client.Active); + if (networkId != long.MinValue) + { + iqClients = iqClients.Where(_client => networkId == _client.NetworkId); + } + else + { + iqClients = iqClients.Where(_client => linkIds.Contains(_client.AliasLinkId)); + } + + // we want to project our results + var iqClientProjection = iqClients.OrderByDescending(_client => _client.LastConnection) + .Select(_client => new PlayerInfo() + { + Name = _client.CurrentAlias.Name, + LevelInt = (int)_client.Level, + LastConnection = _client.LastConnection, + ClientId = _client.ClientId, + }); #if DEBUG == true var iqClientsSql = iqClients.ToSql(); #endif + var clients = await iqClientProjection.ToListAsync(); + + // this is so we don't try to evaluate this in the linq to entities query + foreach (var client in clients) + { + client.Level = ((Permission)client.LevelInt).ToLocalizedLevelName(); + } - return await iqClients.ToListAsync(); + return clients; } } diff --git a/WebfrontCore/Controllers/ClientController.cs b/WebfrontCore/Controllers/ClientController.cs index e75ccc31..cdb5ca6d 100644 --- a/WebfrontCore/Controllers/ClientController.cs +++ b/WebfrontCore/Controllers/ClientController.cs @@ -121,18 +121,7 @@ namespace WebfrontCore.Controllers public async Task FindAsync(string clientName) { - var clients = (await Manager.GetClientService().FindClientsByIdentifier(clientName)) - .OrderByDescending(c => c.LastConnection); - - var clientsDto = clients.Select(c => new PlayerInfo() - { - Name = c.Name, - Level = c.Level.ToLocalizedLevelName(), - LevelInt = (int)c.Level, - LastConnection = c.LastConnection, - ClientId = c.ClientId - }) - .ToList(); + var clientsDto = await Manager.GetClientService().FindClientsByIdentifier(clientName); ViewBag.Title = $"{clientsDto.Count} {Localization["WEBFRONT_CLIENT_SEARCH_MATCHING"]} \"{clientName}\""; return View("Find/Index", clientsDto);