diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index 61d7acf50..f46ea07f8 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -84,18 +84,18 @@ namespace IW4MAdmin if (client.ClientNumber >= 0) { #endif - Logger.WriteInfo($"Client {client} [{client.State.ToString().ToLower()}] disconnecting..."); - Clients[client.ClientNumber] = null; - await client.OnDisconnect(); + Logger.WriteInfo($"Client {client} [{client.State.ToString().ToLower()}] disconnecting..."); + Clients[client.ClientNumber] = null; + await client.OnDisconnect(); - var e = new GameEvent() - { - Origin = client, - Owner = this, - Type = GameEvent.EventType.Disconnect - }; + var e = new GameEvent() + { + Origin = client, + Owner = this, + Type = GameEvent.EventType.Disconnect + }; - Manager.GetEventHandler().AddEvent(e); + Manager.GetEventHandler().AddEvent(e); #if DEBUG == true } #endif @@ -176,10 +176,14 @@ namespace IW4MAdmin finally { - E.Origin?.Unlock(); + if (E.IsBlocking) + { + E.Origin?.Unlock(); + } if (lastException != null) { + Logger.WriteDebug("Last Exception is not null"); throw lastException; } } @@ -555,28 +559,25 @@ namespace IW4MAdmin private async Task OnClientUpdate(EFClient origin) { - var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(origin)); + var client = GetClientsAsList().First(_client => _client.Equals(origin)); - if (client != null) + client.Ping = origin.Ping; + client.Score = origin.Score; + + // update their IP if it hasn't been set yet + if (client.IPAddress == null && + !client.IsBot && + client.State == ClientState.Connected) { - client.Ping = origin.Ping; - client.Score = origin.Score; - - // update their IP if it hasn't been set yet - if (client.IPAddress == null && - !client.IsBot && - client.State == ClientState.Connected) + try { - try - { - await client.OnJoin(origin.IPAddress); - } + await client.OnJoin(origin.IPAddress); + } - catch (Exception e) - { - origin.CurrentServer.Logger.WriteWarning($"Could not execute on join for {origin}"); - origin.CurrentServer.Logger.WriteDebug(e.GetExceptionInfo()); - } + catch (Exception e) + { + origin.CurrentServer.Logger.WriteWarning($"Could not execute on join for {origin}"); + origin.CurrentServer.Logger.WriteDebug(e.GetExceptionInfo()); } } } diff --git a/Plugins/ScriptPlugins/ParserPT6.js b/Plugins/ScriptPlugins/ParserPT6.js index a1d97eed0..2749d76b2 100644 --- a/Plugins/ScriptPlugins/ParserPT6.js +++ b/Plugins/ScriptPlugins/ParserPT6.js @@ -26,7 +26,7 @@ var plugin = { rconParser.Configuration.Dvar.AddMapping(107, 2); rconParser.Configuration.WaitForResponse = false; - rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +(.+) +((?:[A-Z]+|[0-9]+)) +((?:[A-Z]|[0-9]){1,16}) +(.{0,16}) +([0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(-?[0-9]+) +([0-9]+) *$' + rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +(.+) +((?:[A-Z]+|[0-9]+)) +((?:[A-Z]|[0-9]){1,16}) +(.{0,16}) +([0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(-?[0-9]+) +([0-9]+) *$'; rconParser.Configuration.Status.AddMapping(100, 1); rconParser.Configuration.Status.AddMapping(101, 2); rconParser.Configuration.Status.AddMapping(102, 4); diff --git a/Plugins/Stats/Controllers/StatsController.cs b/Plugins/Stats/Controllers/StatsController.cs index f195a40eb..1aaf3c46d 100644 --- a/Plugins/Stats/Controllers/StatsController.cs +++ b/Plugins/Stats/Controllers/StatsController.cs @@ -110,6 +110,7 @@ namespace IW4MAdmin.Plugins.Stats.Web.Controllers .Select(_penalty => new { _penalty.OffenderId, _penalty.PenaltyId, _penalty.When, _penalty.AutomatedOffense }) .FirstOrDefaultAsync(_penalty => _penalty.PenaltyId == penaltyId); + // todo: this can be optimized var iqSnapshotInfo = ctx.Set() .Where(s => s.ClientId == penalty.OffenderId) .Include(s => s.LastStrainAngle) @@ -121,9 +122,6 @@ namespace IW4MAdmin.Plugins.Stats.Web.Controllers .OrderBy(s => s.When) .ThenBy(s => s.Hits); -#if DEBUG == true - var sql = iqSnapshotInfo.ToSql(); -#endif var penaltyInfo = await iqSnapshotInfo.ToListAsync(); if (penaltyInfo.Count > 0) diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 0943ea460..3dd565e9b 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -548,6 +548,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers } } + catch (TaskCanceledException) { } catch (Exception ex) { _log.WriteError("Could not save hit or AC info"); diff --git a/Plugins/Stats/Models/EFACSnapshotVector3.cs b/Plugins/Stats/Models/EFACSnapshotVector3.cs index 2e1215cfa..1401f5aa9 100644 --- a/Plugins/Stats/Models/EFACSnapshotVector3.cs +++ b/Plugins/Stats/Models/EFACSnapshotVector3.cs @@ -1,14 +1,11 @@ -using IW4MAdmin.Plugins.Stats.Models; +using SharedLibraryCore.Database.Models; using SharedLibraryCore.Helpers; -using System; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Text; namespace IW4MAdmin.Plugins.Stats.Models { - public class EFACSnapshotVector3 + public class EFACSnapshotVector3 : SharedEntity { [Key] public int ACSnapshotVector3Id { get; set; } diff --git a/Plugins/Stats/Models/EFClientMessage.cs b/Plugins/Stats/Models/EFClientMessage.cs index ed3baa308..4a4106c1e 100644 --- a/Plugins/Stats/Models/EFClientMessage.cs +++ b/Plugins/Stats/Models/EFClientMessage.cs @@ -1,11 +1,7 @@ using SharedLibraryCore.Database.Models; using System; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace IW4MAdmin.Plugins.Stats.Models { diff --git a/Plugins/Stats/Models/EFClientStatistics.cs b/Plugins/Stats/Models/EFClientStatistics.cs index 7c0e841c1..8bcb518f7 100644 --- a/Plugins/Stats/Models/EFClientStatistics.cs +++ b/Plugins/Stats/Models/EFClientStatistics.cs @@ -3,10 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; - using SharedLibraryCore.Database.Models; namespace IW4MAdmin.Plugins.Stats.Models diff --git a/Plugins/Tests/TestRconParser.cs b/Plugins/Tests/TestRconParser.cs index b1c6d8aba..e8becb30b 100644 --- a/Plugins/Tests/TestRconParser.cs +++ b/Plugins/Tests/TestRconParser.cs @@ -14,7 +14,7 @@ namespace Tests public override string Version => "test"; - public override async Task> GetStatusAsync(Connection connection) + public override async Task<(List, string)> GetStatusAsync(Connection connection) { var clientList = new List(); @@ -32,7 +32,7 @@ namespace Tests }); } - return clientList.Count > 0 ? clientList : FakeClients; + return clientList.Count > 0 ? (clientList, "mp_rust") : (FakeClients, "mp_rust"); } } } diff --git a/Plugins/Web/StatsWeb/Views/Stats/_PenaltyInfo.cshtml b/Plugins/Web/StatsWeb/Views/Stats/_PenaltyInfo.cshtml index 2fbf38a8f..fe20c4bea 100644 --- a/Plugins/Web/StatsWeb/Views/Stats/_PenaltyInfo.cshtml +++ b/Plugins/Web/StatsWeb/Views/Stats/_PenaltyInfo.cshtml @@ -10,12 +10,12 @@ var snapProperties = Model.First().GetType().GetProperties(); foreach (var prop in snapProperties) { - @if (prop.Name.EndsWith("Id") || new[] { "Active", "Client", "PredictedViewAngles" }.Contains(prop.Name)) + @if ((prop.Name.EndsWith("Id") && prop.Name != "WeaponId") || new[] { "Active", "Client", "PredictedViewAngles" }.Contains(prop.Name)) { continue; } - @prop.Name — @prop.GetValue(snapshot)
+ @prop.Name — @prop.GetValue(snapshot).ToString()
}
} diff --git a/SharedLibraryCore/Database/DatabaseContext.cs b/SharedLibraryCore/Database/DatabaseContext.cs index 66a568753..c0201dff8 100644 --- a/SharedLibraryCore/Database/DatabaseContext.cs +++ b/SharedLibraryCore/Database/DatabaseContext.cs @@ -10,6 +10,8 @@ using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; namespace SharedLibraryCore.Database { @@ -69,8 +71,8 @@ namespace SharedLibraryCore.Database protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - // optionsBuilder.UseLoggerFactory(_loggerFactory) - // .EnableSensitiveDataLogging(); + // optionsBuilder.UseLoggerFactory(_loggerFactory) + // .EnableSensitiveDataLogging(); if (string.IsNullOrEmpty(_ConnectionString)) { @@ -102,6 +104,41 @@ namespace SharedLibraryCore.Database } } + private void SetAuditColumns() + { + return; + var entries = ChangeTracker + .Entries() + .Where(e => e.Entity is SharedEntity && ( + e.State == EntityState.Added + || e.State == EntityState.Modified)).ToList(); + + foreach (var entityEntry in entries) + { + if (entityEntry.State == EntityState.Added) + { + //((SharedEntity)entityEntry.Entity).CreatedDateTime = DateTime.UtcNow; + } + + else + { + //((SharedEntity)entityEntry.Entity).UpdatedDateTime = DateTime.UtcNow; + } + } + } + + public override Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) + { + SetAuditColumns(); + return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); + } + + public override int SaveChanges() + { + SetAuditColumns(); + return base.SaveChanges(); + } + protected override void OnModelCreating(ModelBuilder modelBuilder) { // make network id unique diff --git a/SharedLibraryCore/Database/Models/EFAlias.cs b/SharedLibraryCore/Database/Models/EFAlias.cs index 0cba62ac2..f9be14c2d 100644 --- a/SharedLibraryCore/Database/Models/EFAlias.cs +++ b/SharedLibraryCore/Database/Models/EFAlias.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace SharedLibraryCore.Database.Models { - public partial class EFAlias + public partial class EFAlias : SharedEntity { [Key] public int AliasId { get; set; } diff --git a/SharedLibraryCore/Database/Models/SharedEntity.cs b/SharedLibraryCore/Database/Models/SharedEntity.cs index 269158546..cee40ed84 100644 --- a/SharedLibraryCore/Database/Models/SharedEntity.cs +++ b/SharedLibraryCore/Database/Models/SharedEntity.cs @@ -1,13 +1,25 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations.Schema; namespace SharedLibraryCore.Database.Models { public class SharedEntity { + /// + /// indicates if the entity is active + /// public bool Active { get; set; } = true; + + ///// + ///// Specifies when the entity was created + ///// + //[Column(TypeName="datetime")] + //public DateTime CreatedDateTime { get; set; } + + ///// + ///// Specifies when the entity was updated + ///// + //[Column(TypeName = "datetime")] + //public DateTime? UpdatedDateTime { get;set; } } } diff --git a/SharedLibraryCore/Interfaces/IMiddlewareAction.cs b/SharedLibraryCore/Interfaces/IMiddlewareAction.cs index b8e4b7d7c..995efe598 100644 --- a/SharedLibraryCore/Interfaces/IMiddlewareAction.cs +++ b/SharedLibraryCore/Interfaces/IMiddlewareAction.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace SharedLibraryCore.Interfaces { diff --git a/SharedLibraryCore/Migrations/20191030000713_EnforceUniqueIndexForEFAliasIPName.cs b/SharedLibraryCore/Migrations/20191030000713_EnforceUniqueIndexForEFAliasIPName.cs index a3d604e94..1415f32c3 100644 --- a/SharedLibraryCore/Migrations/20191030000713_EnforceUniqueIndexForEFAliasIPName.cs +++ b/SharedLibraryCore/Migrations/20191030000713_EnforceUniqueIndexForEFAliasIPName.cs @@ -8,11 +8,55 @@ namespace SharedLibraryCore.Migrations { if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite") { - migrationBuilder.Sql(@"DELETE FROM EFAlias WHERE AliasId IN ( - SELECT AliasId from ( - SELECT AliasId, Name, Min(DateAdded), IPAddress FROM EFAlias where (IPAddress, Name) in (SELECT DISTINCT IPAddress, Name FROM EFAlias GROUP BY EFAlias.IPAddress, Name HAVING count(IPAddress) > 1 AND count(Name) > 1) - GROUP BY IPAddress ORDER BY IPAddress))", true); - migrationBuilder.Sql(@"CREATE UNIQUE INDEX IX_EFAlias_Name_IPAddress ON EFAlias ( IPAddress, Name );", true); + migrationBuilder.Sql(@"DROP TABLE IF EXISTS DUPLICATE_ALIASES; + CREATE TABLE DUPLICATE_ALIASES AS +SELECT + MIN(AliasId) MIN, + MAX(AliasId) MAX, + LinkId +FROM + EFAlias +WHERE + (IPAddress, NAME) IN( + SELECT DISTINCT + IPAddress, + NAME + FROM + EFAlias + GROUP BY + EFAlias.IPAddress, + NAME + HAVING + COUNT(IPAddress) > 1 AND COUNT(NAME) > 1 +) +GROUP BY + IPAddress +ORDER BY + IPAddress; + + UPDATE + EFClients +SET CurrentAliasId = (SELECT MAX FROM DUPLICATE_ALIASES WHERE CurrentAliasId = MIN) +WHERE + CurrentAliasId IN( + SELECT + MIN + FROM + DUPLICATE_ALIASES +); + DELETE + FROM + EFAlias +WHERE + AliasId IN( + SELECT + MIN + FROM + DUPLICATE_ALIASES +); + + DROP TABLE + DUPLICATE_ALIASES;"); return; } @@ -77,30 +121,57 @@ DROP TABLE else { - migrationBuilder.Sql(@"DELETE -FROM ""EFAlias"" -WHERE ""AliasId"" -IN -( - SELECT MIN(""AliasId"") AliasId - - FROM ""EFAlias"" WHERE(""IPAddress"", ""Name"") - - IN - ( - SELECT DISTINCT ""IPAddress"", ""Name"" - - FROM ""EFAlias"" - - GROUP BY ""EFAlias"".""IPAddress"", ""Name"" - - HAVING COUNT(""IPAddress"") > 1 AND COUNT(""Name"") > 1 - ) - - GROUP BY ""IPAddress"" - - ORDER BY ""IPAddress"" -)", true); + migrationBuilder.Sql(@"CREATE TEMPORARY TABLE DUPLICATE_ALIASES AS +SELECT + MIN(""AliasId"") ""MIN"", + MAX(""AliasId"") ""MAX"", + MIN(""LinkId"") ""LinkId"" +FROM + ""EFAlias"" +WHERE + (""IPAddress"", ""Name"") IN( + SELECT DISTINCT + ""IPAddress"", + ""Name"" + FROM + ""EFAlias"" + GROUP BY + ""EFAlias"".""IPAddress"", + ""Name"" + HAVING + COUNT(""IPAddress"") > 1 AND COUNT(""Name"") > 1 +) +GROUP BY + ""IPAddress"" +ORDER BY + ""IPAddress""; +UPDATE + ""EFClients"" AS ""Client"" +SET + ""CurrentAliasId"" = ""Duplicate"".""MAX"" +FROM + DUPLICATE_ALIASES ""Duplicate"" +WHERE + ""Client"".""CurrentAliasId"" IN( + SELECT + ""MIN"" + FROM + DUPLICATE_ALIASES +) +AND + ""Client"".""CurrentAliasId"" = ""Duplicate"".""MIN""; +DELETE +FROM + ""EFAlias"" +WHERE + ""AliasId"" IN( + SELECT + ""MIN"" + FROM + DUPLICATE_ALIASES +); +DROP TABLE + DUPLICATE_ALIASES;"); } migrationBuilder.CreateIndex( @@ -112,9 +183,6 @@ IN protected override void Down(MigrationBuilder migrationBuilder) { - migrationBuilder.DropIndex( - name: "IX_EFAlias_Name_IPAddress", - table: "EFAlias"); } } } diff --git a/SharedLibraryCore/PartialEntities/EFClient.cs b/SharedLibraryCore/PartialEntities/EFClient.cs index 6c1d14574..6fc04c6a3 100644 --- a/SharedLibraryCore/PartialEntities/EFClient.cs +++ b/SharedLibraryCore/PartialEntities/EFClient.cs @@ -540,6 +540,7 @@ namespace SharedLibraryCore.Database.Models else { + CurrentServer.Logger.WriteDebug($"Creating join event for {this}"); var e = new GameEvent() { Type = GameEvent.EventType.Join, diff --git a/SharedLibraryCore/Services/ClientService.cs b/SharedLibraryCore/Services/ClientService.cs index 3733fb67f..a7c9ce578 100644 --- a/SharedLibraryCore/Services/ClientService.cs +++ b/SharedLibraryCore/Services/ClientService.cs @@ -103,8 +103,6 @@ namespace SharedLibraryCore.Services private async Task UpdateAlias(string name, int? ip, EFClient entity, DatabaseContext context) { - entity.CurrentServer.Manager.GetLogger(0).WriteDebug($"Begin update alias for {entity}"); - // entity is the tracked db context item // get all aliases by IP address and LinkId var iqAliases = context.Aliases @@ -216,8 +214,6 @@ namespace SharedLibraryCore.Services entity.CurrentAliasId = 0; await context.SaveChangesAsync(); } - - entity.CurrentServer.Manager.GetLogger(0).WriteDebug($"End update alias for {entity}"); } /// @@ -308,7 +304,8 @@ namespace SharedLibraryCore.Services { Name = _client.CurrentAlias.Name, IPAddress = _client.CurrentAlias.IPAddress - } + }, + TotalConnectionTime = _client.TotalConnectionTime }) .FirstOrDefault(_client => _client.ClientId == entityId); @@ -362,8 +359,6 @@ namespace SharedLibraryCore.Services EF.CompileAsyncQuery((DatabaseContext context, long networkId) => context.Clients .Include(c => c.CurrentAlias) - //.Include(c => c.AliasLink.Children) - //.Include(c => c.ReceivedPenalties) .Select(_client => new EFClient() { ClientId = _client.ClientId, @@ -373,7 +368,8 @@ namespace SharedLibraryCore.Services FirstConnection = _client.FirstConnection, LastConnection = _client.LastConnection, Masked = _client.Masked, - NetworkId = _client.NetworkId + NetworkId = _client.NetworkId, + TotalConnectionTime = _client.TotalConnectionTime }) .FirstOrDefault(c => c.NetworkId == networkId) ); diff --git a/SharedLibraryCore/SharedLibraryCore.csproj b/SharedLibraryCore/SharedLibraryCore.csproj index ded7da951..5e3c4233f 100644 --- a/SharedLibraryCore/SharedLibraryCore.csproj +++ b/SharedLibraryCore/SharedLibraryCore.csproj @@ -34,26 +34,32 @@ + + + + + + - - - + + + all runtime; build; native; contentfiles; analyzers - - - - - - - - + + + + + + + + - + diff --git a/WebfrontCore/Middleware/CustomCssAccentMiddlewareAction.cs b/WebfrontCore/Middleware/CustomCssAccentMiddlewareAction.cs index 3d6542116..cf98a45bd 100644 --- a/WebfrontCore/Middleware/CustomCssAccentMiddlewareAction.cs +++ b/WebfrontCore/Middleware/CustomCssAccentMiddlewareAction.cs @@ -45,7 +45,7 @@ namespace WebfrontCore.Middleware } } - public async Task Invoke(string original) + public Task Invoke(string original) { foreach (var color in ColorReplacements) { @@ -57,7 +57,7 @@ namespace WebfrontCore.Middleware } } - return original; + return Task.FromResult(original); } ///