From 9bdd7d1b8a16700dfc7b3ed92f43e0099e275c20 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Wed, 7 Nov 2018 20:30:11 -0600 Subject: [PATCH] More work modifying client stuff --- Application/Core/ClientAuthentication.cs | 83 ------ Application/EventParsers/IW4EventParser.cs | 52 ++-- Application/EventParsers/IW5EventParser.cs | 2 +- Application/IO/GameLogEventDetection.cs | 1 + Application/{Server.cs => IW4MServer.cs} | 257 +++++++++++------- Application/Manager.cs | 24 +- Master/requirements.txt | 20 +- Plugins/Stats/Helpers/StatManager.cs | 1 - SharedLibraryCore/Database/Models/EFClient.cs | 4 +- SharedLibraryCore/Events/GameEvent.cs | 33 ++- .../Interfaces/IClientAuthentication.cs | 28 -- SharedLibraryCore/Objects/EFClient.cs | 47 ++-- SharedLibraryCore/RCon/Connection.cs | 8 +- SharedLibraryCore/Server.cs | 2 +- 14 files changed, 255 insertions(+), 307 deletions(-) delete mode 100644 Application/Core/ClientAuthentication.cs rename Application/{Server.cs => IW4MServer.cs} (85%) delete mode 100644 SharedLibraryCore/Interfaces/IClientAuthentication.cs diff --git a/Application/Core/ClientAuthentication.cs b/Application/Core/ClientAuthentication.cs deleted file mode 100644 index fa064493c..000000000 --- a/Application/Core/ClientAuthentication.cs +++ /dev/null @@ -1,83 +0,0 @@ -using SharedLibraryCore.Database.Models; -using SharedLibraryCore.Interfaces; -using SharedLibraryCore.Objects; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace IW4MAdmin.Application.Core -{ - class ClientAuthentication : IClientAuthentication - { - private Queue ClientAuthenticationQueue; - private Dictionary AuthenticatedClients; - - public ClientAuthentication() - { - ClientAuthenticationQueue = new Queue(); - AuthenticatedClients = new Dictionary(); - } - - public void AuthenticateClients(IList clients) - { - // we need to un-auth all the clients that have disconnected - var clientNetworkIds = clients.Select(c => c.NetworkId); - var clientsToRemove = AuthenticatedClients.Keys.Where(c => !clientNetworkIds.Contains(c)); - // remove them - foreach (long Id in clientsToRemove.ToList()) - { - AuthenticatedClients.Remove(Id); - } - - // loop through the polled clients to see if they've been authenticated yet - foreach (var client in clients) - { - // they've not been authenticated - if (!AuthenticatedClients.TryGetValue(client.NetworkId, out EFClient value)) - { - // authenticate them - client.State = EFClient.ClientState.Authenticated; - AuthenticatedClients.Add(client.NetworkId, client); - } - else - { - // this update their ping - // todo: this seems kinda hacky - value.Ping = client.Ping; - value.Score = client.Score; - } - } - - // empty out the queue of clients detected through log - while (ClientAuthenticationQueue.Count > 0) - { - // grab each client that's connected via log - var clientToAuthenticate = ClientAuthenticationQueue.Dequeue(); - // if they're not already authed, auth them - if (!AuthenticatedClients.TryGetValue(clientToAuthenticate.NetworkId, out EFClient value)) - { - // authenticate them - clientToAuthenticate.State = EFClient.ClientState.Authenticated; - AuthenticatedClients.Add(clientToAuthenticate.NetworkId, clientToAuthenticate); - } - } - } - - public IList GetAuthenticatedClients() - { - if (AuthenticatedClients.Values.Count > 18) - { - Program.ServerManager.GetLogger(0).WriteError($"auth client count is {AuthenticatedClients.Values.Count}, this is bad"); - return AuthenticatedClients.Values.Take(18).ToList(); - } - - return AuthenticatedClients.Values.ToList(); - } - - public void RequestClientAuthentication(EFClient client) - { - ClientAuthenticationQueue.Enqueue(client); - } - } -} diff --git a/Application/EventParsers/IW4EventParser.cs b/Application/EventParsers/IW4EventParser.cs index cdbb5fd79..4e37bed3f 100644 --- a/Application/EventParsers/IW4EventParser.cs +++ b/Application/EventParsers/IW4EventParser.cs @@ -144,7 +144,7 @@ namespace IW4MAdmin.Application.EventParsers { return new GameEvent() { - Type = GameEvent.EventType.Join, + Type = GameEvent.EventType.PreConnect, Data = logLine, Owner = server, Origin = new EFClient() @@ -159,26 +159,26 @@ namespace IW4MAdmin.Application.EventParsers } } - //if (eventType == "Q") - //{ - // var regexMatch = Regex.Match(logLine, @"^(Q;)(.{1,32});([0-9]+);(.*)$"); - // if (regexMatch.Success) - // { - // return new GameEvent() - // { - // Type = GameEvent.EventType.Quit, - // Data = logLine, - // Owner = server, - // Origin = new Player() - // { - // Name = regexMatch.Groups[4].ToString().StripColors(), - // NetworkId = regexMatch.Groups[2].ToString().ConvertLong(), - // ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()), - // State = Player.ClientState.Connecting - // } - // }; - // } - //} + if (eventType == "Q") + { + var regexMatch = Regex.Match(logLine, @"^(Q;)(.{1,32});([0-9]+);(.*)$"); + if (regexMatch.Success) + { + return new GameEvent() + { + Type = GameEvent.EventType.PreDisconnect, + Data = logLine, + Owner = server, + Origin = new EFClient() + { + Name = regexMatch.Groups[4].ToString().StripColors(), + NetworkId = regexMatch.Groups[2].ToString().ConvertLong(), + ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()), + State = EFClient.ClientState.Disconnecting + } + }; + } + } if (eventType.Contains("ExitLevel")) { @@ -186,14 +186,8 @@ namespace IW4MAdmin.Application.EventParsers { Type = GameEvent.EventType.MapEnd, Data = lineSplit[0], - Origin = new EFClient() - { - ClientId = 1 - }, - Target = new EFClient() - { - ClientId = 1 - }, + Origin = Utilities.IW4MAdminClient(server), + Target = Utilities.IW4MAdminClient(server), Owner = server }; } diff --git a/Application/EventParsers/IW5EventParser.cs b/Application/EventParsers/IW5EventParser.cs index 429b1bc32..4f6e76119 100644 --- a/Application/EventParsers/IW5EventParser.cs +++ b/Application/EventParsers/IW5EventParser.cs @@ -33,7 +33,7 @@ namespace IW4MAdmin.Application.EventParsers return new GameEvent() { - Type = GameEvent.EventType.Join, + Type = GameEvent.EventType.PreConnect, Origin = new EFClient() { ClientId = 1 diff --git a/Application/IO/GameLogEventDetection.cs b/Application/IO/GameLogEventDetection.cs index caff3a527..7b2e914f0 100644 --- a/Application/IO/GameLogEventDetection.cs +++ b/Application/IO/GameLogEventDetection.cs @@ -79,6 +79,7 @@ namespace IW4MAdmin.Application.IO foreach (var ev in events) { Server.Manager.GetEventHandler().AddEvent(ev); + await ev.WaitAsync(); } PreviousFileSize = fileSize; diff --git a/Application/Server.cs b/Application/IW4MServer.cs similarity index 85% rename from Application/Server.cs rename to Application/IW4MServer.cs index 3b61d5767..89fb970df 100644 --- a/Application/Server.cs +++ b/Application/IW4MServer.cs @@ -32,6 +32,7 @@ namespace IW4MAdmin public override int GetHashCode() { + // hack: my laziness if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28965") { return 886229536; @@ -56,16 +57,6 @@ namespace IW4MAdmin return Id; } - public async Task OnClientJoined(EFClient polledClient) - { - var existingClient = Clients[polledClient.ClientNumber]; - - if (existingClient != null) - { - await existingClient.OnJoin(polledClient.IPAddress); - } - } - override public async Task OnClientConnected(EFClient clientFromLog) { Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved"); @@ -119,40 +110,49 @@ namespace IW4MAdmin Clients[client.ClientNumber] = client; client.OnConnect(); + // this only happens the preconnect event occurred from RCon polling + if (clientFromLog.IPAddress != 0) + { + await client.OnJoin(clientFromLog.IPAddress); + } + client.State = EFClient.ClientState.Connected; +#if DEBUG == true + Logger.WriteDebug($"End PreConnect for {client}"); +#endif + var e = new GameEvent() + { + Origin = client, + Owner = this, + Type = GameEvent.EventType.Connect + }; + + Manager.GetEventHandler().AddEvent(e); } catch (Exception ex) { - Logger.WriteError($"{loc["SERVER_ERROR_ADDPLAYER"]} {clientFromLog.Name}::{clientFromLog.NetworkId}"); - Logger.WriteDebug(ex.Message); - Logger.WriteDebug(ex.StackTrace); + Logger.WriteError($"{loc["SERVER_ERROR_ADDPLAYER"]} {clientFromLog}"); + Logger.WriteError(ex.GetExceptionInfo()); } } - //Remove player by CLIENT NUMBER - override public async Task RemoveClient(int cNum) + override public async Task OnClientDisconnected(EFClient client) { - if (cNum >= 0 && Clients[cNum] != null) + Logger.WriteInfo($"Client {client} [{client.State.ToString().ToLower()}] disconnecting..."); + await client.OnDisconnect(); + Clients[client.ClientNumber] = null; +#if DEBUG == true + Logger.WriteDebug($"End PreDisconnect for {client}"); +#endif + var e = new GameEvent() { - EFClient Leaving = Clients[cNum]; + Origin = client, + Owner = this, + Type = GameEvent.EventType.Disconnect + }; - // occurs when the player disconnects via log before being authenticated by RCon - if (Leaving.State != EFClient.ClientState.Connected) - { - Clients[cNum] = null; - } - - else - { - Logger.WriteInfo($"Client {Leaving} [{Leaving.State.ToString().ToLower()}] disconnecting..."); - Leaving.State = EFClient.ClientState.Disconnecting; - Leaving.TotalConnectionTime += Leaving.ConnectionLength; - Leaving.LastConnection = DateTime.UtcNow; - await Manager.GetClientService().Update(Leaving); - Clients[cNum] = null; - } - } + Manager.GetEventHandler().AddEvent(e); } public override async Task ExecuteEvent(GameEvent E) @@ -218,27 +218,34 @@ namespace IW4MAdmin /// override protected async Task ProcessEvent(GameEvent E) { - if (E.Type == GameEvent.EventType.Connect) + if (E.Type == GameEvent.EventType.PreConnect) { - E.Origin.State = EFClient.ClientState.Authenticated; - await OnClientConnected(E.Origin); + bool clientExists = GetClientsAsList().Exists(_client => _client.NetworkId.Equals(E.Origin)); - ChatHistory.Add(new ChatInfo() + if (!clientExists) { - Name = E.Origin.Name, - Message = "CONNECTED", - Time = DateTime.UtcNow - }); +#if DEBUG == true + Logger.WriteDebug($"Begin PreConnect for {E.Origin}"); +#endif + await OnClientConnected(E.Origin); - if (E.Origin.Level > EFClient.Permission.Moderator) - { - E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count)); + ChatHistory.Add(new ChatInfo() + { + Name = E.Origin.Name, + Message = "CONNECTED", + Time = DateTime.UtcNow + }); + + if (E.Origin.Level > EFClient.Permission.Moderator) + { + E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count)); + } } - } - else if (E.Type == GameEvent.EventType.Join) - { - await OnClientJoined(E.Origin); + else + { + return false; + } } else if (E.Type == GameEvent.EventType.Flag) @@ -303,13 +310,9 @@ namespace IW4MAdmin else if (E.Type == GameEvent.EventType.Quit) { - var origin = Clients.FirstOrDefault(p => p != null && p.NetworkId == E.Origin.NetworkId); + var origin = GetClientsAsList().FirstOrDefault(_client => _client.NetworkId.Equals(E.Origin)); - if (origin != null && - // we only want to forward the event if they are connected. - origin.State == EFClient.ClientState.Connected && - // make sure we don't get the disconnect event from every time the game ends - origin.ConnectionLength < Manager.GetApplicationSettings().Configuration().RConPollRate) + if (origin != null) { var e = new GameEvent() { @@ -321,29 +324,45 @@ namespace IW4MAdmin Manager.GetEventHandler().AddEvent(e); } - else if (origin != null && - origin.State != EFClient.ClientState.Connected) + else { - await RemoveClient(origin.ClientNumber); + return false; } } - else if (E.Type == GameEvent.EventType.Disconnect) + else if (E.Type == GameEvent.EventType.PreDisconnect) { - ChatHistory.Add(new ChatInfo() - { - Name = E.Origin.Name, - Message = "DISCONNECTED", - Time = DateTime.UtcNow - }); + // predisconnect comes from minimal rcon polled players and minimal log players + // so we need to disconnect the "full" version of the client + var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin)); - var currentState = E.Origin.State; - await RemoveClient(E.Origin.ClientNumber); - - if (currentState != EFClient.ClientState.Connected) + if (client != null) { - throw new ServerException("Disconnecting player was not in a connected state"); +#if DEBUG == true + Logger.WriteDebug($"Begin PreDisconnect for {client}"); +#endif + ChatHistory.Add(new ChatInfo() + { + Name = client.Name, + Message = "DISCONNECTED", + Time = DateTime.UtcNow + }); + + await OnClientDisconnected(client); } + + else + { + return false; + } + } + + else if (E.Type == GameEvent.EventType.Update) + { +#if DEBUG == true + Logger.WriteDebug($"Begin Update for {E.Origin}"); +#endif + await OnClientUpdate(E.Origin); } if (E.Type == GameEvent.EventType.Say) @@ -440,6 +459,24 @@ namespace IW4MAdmin return true; } + private Task OnClientUpdate(EFClient origin) + { + var client = Clients[origin.ClientNumber]; + + if (client != null) + { + client.Ping = origin.Ping; + client.Score = origin.Score; + + if (origin.IPAddress == 0) + { + return client.OnJoin(origin.IPAddress); + } + } + + return Task.CompletedTask; + } + /// /// lists the connecting and disconnecting clients via RCon response /// array index 0 = connecting clients @@ -471,9 +508,15 @@ namespace IW4MAdmin } var disconnectingClients = currentClients.Except(polledClients); - var connectingClients = polledClients.Except(currentClients.Where(c => c.State == EFClient.ClientState.Connected)); + var connectingClients = polledClients.Except(currentClients); + var updatedClients = polledClients.Except(connectingClients); - return new List[] { connectingClients.ToList(), disconnectingClients.ToList() }; + return new List[] + { + connectingClients.ToList(), + disconnectingClients.ToList(), + updatedClients.ToList() + }; } DateTime start = DateTime.Now; @@ -484,21 +527,30 @@ namespace IW4MAdmin { try { + #region SHUTDOWN if (Manager.ShutdownRequested()) { - // todo: fix up disconnect - //for (int i = 0; i < EFClients.Count; i++) - // await RemoveClient(i); + foreach (var client in GetClientsAsList()) + { + var e = new GameEvent() + { + Type = GameEvent.EventType.PreDisconnect, + Origin = client, + Owner = this, + }; + + Manager.GetEventHandler().AddEvent(e); + await e.WaitAsync(); + } foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins) { await plugin.OnUnloadAsync(); } - } - // only check every 2 minutes if the server doesn't seem to be responding - /* if ((DateTime.Now - LastPoll).TotalMinutes < 0.5 && ConnectionErrors >= 1) - return true;*/ + return true; + } + #endregion try { @@ -514,7 +566,7 @@ namespace IW4MAdmin var e = new GameEvent() { - Type = GameEvent.EventType.Disconnect, + Type = GameEvent.EventType.PreDisconnect, Origin = disconnectingClient, Owner = this }; @@ -531,16 +583,9 @@ namespace IW4MAdmin // this are our new connecting clients foreach (var client in polledClients[0]) { - // this prevents duplicate events from being sent to the event api - if (GetClientsAsList().Count(c => c.NetworkId == client.NetworkId && - c.State == EFClient.ClientState.Connected) != 0) - { - continue; - } - var e = new GameEvent() { - Type = GameEvent.EventType.Connect, + Type = GameEvent.EventType.PreConnect, Origin = client, Owner = this }; @@ -552,11 +597,29 @@ namespace IW4MAdmin // wait for all the connect tasks to finish await Task.WhenAll(waiterList.Select(e => e.WaitAsync(10 * 1000))); + waiterList.Clear(); + // these are the clients that have updated + foreach (var client in polledClients[2]) + { + var e = new GameEvent() + { + Type = GameEvent.EventType.Update, + Origin = client, + Owner = this + }; + + Manager.GetEventHandler().AddEvent(e); + waiterList.Add(e); + } + + await Task.WhenAll(waiterList.Select(e => e.WaitAsync(10 * 1000))); + if (ConnectionErrors > 0) { Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}"); Throttled = false; } + ConnectionErrors = 0; LastPoll = DateTime.Now; } @@ -576,20 +639,6 @@ namespace IW4MAdmin LastMessage = DateTime.Now - start; lastCount = DateTime.Now; - // todo: re-enable on tick - /* - if ((DateTime.Now - tickTime).TotalMilliseconds >= 1000) - { - foreach (var Plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins) - { - if (cts.IsCancellationRequested) - break; - - await Plugin.OnTickAsync(this); - } - tickTime = DateTime.Now; - }*/ - // update the player history if ((lastCount - playerCountStart).TotalMinutes >= SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval) { @@ -849,7 +898,7 @@ namespace IW4MAdmin #endif #if DEBUG - await Target.CurrentServer.RemoveClient(Target.ClientNumber); + await Target.CurrentServer.OnClientDisconnected(Target); #endif var newPenalty = new Penalty() @@ -887,7 +936,7 @@ namespace IW4MAdmin await Target.CurrentServer.ExecuteCommandAsync(formattedKick); } #else - await Target.CurrentServer.RemoveClient(Target.ClientNumber); + await Target.CurrentServer.OnClientDisconnected(Target); #endif Penalty newPenalty = new Penalty() @@ -933,7 +982,7 @@ namespace IW4MAdmin string formattedString = String.Format(RconParser.GetCommandPrefixes().Kick, Target.ClientNumber, $"{loc["SERVER_BAN_TEXT"]} - ^5{Message} ^7({loc["SERVER_BAN_APPEAL"]} {Website})^7"); await Target.CurrentServer.ExecuteCommandAsync(formattedString); #else - await Target.CurrentServer.RemoveClient(Target.ClientNumber); + await Target.CurrentServer.OnClientDisconnected(Target); #endif } diff --git a/Application/Manager.cs b/Application/Manager.cs index b9b3bf8f2..dd4206272 100644 --- a/Application/Manager.cs +++ b/Application/Manager.cs @@ -85,29 +85,7 @@ namespace IW4MAdmin.Application } try - { - // if the origin client is not in an authorized state (detected by RCon) don't execute the event - if (GameEvent.ShouldOriginEventBeDelayed(newEvent)) - { - Logger.WriteDebug($"Delaying origin execution of event type {newEvent.Type} for {newEvent.Origin} because they are not authed"); - if (newEvent.Type == GameEvent.EventType.Command) - { - newEvent.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["SERVER_DELAYED_EVENT_WAIT"]); - } - - // offload it to the player to keep - newEvent.Origin.DelayedEvents.Enqueue(newEvent); - } - - // if the target client is not in an authorized state (detected by RCon) don't execute the event - else if (GameEvent.ShouldTargetEventBeDelayed(newEvent)) - { - Logger.WriteDebug($"Delaying target execution of event type {newEvent.Type} for {newEvent.Target} because they are not authed"); - // offload it to the player to keep - newEvent.Target.DelayedEvents.Enqueue(newEvent); - } - - else + { { await newEvent.Owner.ExecuteEvent(newEvent); diff --git a/Master/requirements.txt b/Master/requirements.txt index e7089d9ce..424e53036 100644 --- a/Master/requirements.txt +++ b/Master/requirements.txt @@ -1,22 +1,26 @@ aniso8601==3.0.2 +APScheduler==3.5.3 +certifi==2018.10.15 +chardet==3.0.4 click==6.7 Flask==1.0.2 Flask-JWT==0.3.2 Flask-JWT-Extended==3.8.1 Flask-RESTful==0.3.6 +idna==2.7 itsdangerous==0.24 Jinja2==2.10 MarkupSafe==1.0 marshmallow==3.0.0b8 pip==9.0.3 -PyJWT==1.4.2 -pytz==2018.5 -setuptools==39.0.1 -six==1.11.0 -Werkzeug==0.14.1 -certifi==2018.10.15 -chardet==3.0.4 -idna==2.7 psutil==5.4.8 +pygal==2.4.0 +PyJWT==1.4.2 +pytz==2018.7 requests==2.20.0 +setuptools==40.5.0 +six==1.11.0 +timeago==1.0.8 +tzlocal==1.5.1 urllib3==1.24 +Werkzeug==0.14.1 diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 90ff3a2f0..f5a0e2867 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -244,7 +244,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers { int serverId = pl.CurrentServer.GetHashCode(); - if (!Servers.ContainsKey(serverId)) { Log.WriteError($"[Stats::AddPlayer] Server with id {serverId} could not be found"); diff --git a/SharedLibraryCore/Database/Models/EFClient.cs b/SharedLibraryCore/Database/Models/EFClient.cs index d3b8f42fa..74b3c907e 100644 --- a/SharedLibraryCore/Database/Models/EFClient.cs +++ b/SharedLibraryCore/Database/Models/EFClient.cs @@ -41,13 +41,13 @@ namespace SharedLibraryCore.Database.Models public virtual string Name { get { return CurrentAlias.Name; } - set { } + set { CurrentAlias.Name = value; } } [NotMapped] public virtual int IPAddress { get { return CurrentAlias.IPAddress; } - set { } + set { CurrentAlias.IPAddress = value; } } [NotMapped] diff --git a/SharedLibraryCore/Events/GameEvent.cs b/SharedLibraryCore/Events/GameEvent.cs index ca3e455b5..30d106e50 100644 --- a/SharedLibraryCore/Events/GameEvent.cs +++ b/SharedLibraryCore/Events/GameEvent.cs @@ -1,8 +1,7 @@ -using System; +using SharedLibraryCore.Database.Models; +using System; using System.Threading; using System.Threading.Tasks; -using SharedLibraryCore.Database.Models; -using SharedLibraryCore.Objects; namespace SharedLibraryCore { @@ -74,6 +73,18 @@ namespace SharedLibraryCore /// the current map changed /// MapChange, + /// + /// a client was detected as starting to connect + /// + PreConnect, + /// + /// a client was detecting as starting to disconnect + /// + PreDisconnect, + /// + /// a client's information was updated + /// + Update, // events "generated" by clients /// @@ -159,7 +170,10 @@ namespace SharedLibraryCore } static long NextEventId; - static long GetNextEventId() => Interlocked.Increment(ref NextEventId); + static long GetNextEventId() + { + return Interlocked.Increment(ref NextEventId); + } public GameEvent() { @@ -186,11 +200,14 @@ namespace SharedLibraryCore /// asynchronously wait for GameEvent to be processed /// /// waitable task - public Task WaitAsync(int timeOut = int.MaxValue) => Task.Run(() => + public Task WaitAsync(int timeOut = int.MaxValue) { - OnProcessed.Wait(timeOut); - return this; - }); + return Task.Run(() => + { + OnProcessed.Wait(timeOut); + return this; + }); + } /// /// determine whether an event should be delayed or not diff --git a/SharedLibraryCore/Interfaces/IClientAuthentication.cs b/SharedLibraryCore/Interfaces/IClientAuthentication.cs deleted file mode 100644 index e83ed2db4..000000000 --- a/SharedLibraryCore/Interfaces/IClientAuthentication.cs +++ /dev/null @@ -1,28 +0,0 @@ -using SharedLibraryCore.Database.Models; -using SharedLibraryCore.Objects; -using System; -using System.Collections.Generic; -using System.Text; - -namespace SharedLibraryCore.Interfaces -{ - public interface IClientAuthentication - { - /// - /// request authentication when a client join event - /// occurs in the log, as no IP is given - /// - /// client that has joined from the log - void RequestClientAuthentication(EFClient client); - /// - /// get all clients that have been authenticated by the status poll - /// - /// list of all authenticated clients - IList GetAuthenticatedClients(); - /// - /// authenticate a list of clients from status poll - /// - /// list of clients to authenticate - void AuthenticateClients(IList clients); - } -} diff --git a/SharedLibraryCore/Objects/EFClient.cs b/SharedLibraryCore/Objects/EFClient.cs index 758b4fa68..71c9a5ed1 100644 --- a/SharedLibraryCore/Objects/EFClient.cs +++ b/SharedLibraryCore/Objects/EFClient.cs @@ -1,5 +1,4 @@ -using SharedLibraryCore.Database.Models; -using SharedLibraryCore.Objects; +using SharedLibraryCore.Objects; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; @@ -18,11 +17,6 @@ namespace SharedLibraryCore.Database.Models /// Connecting, /// - /// represents when the client has been parsed by RCon, - /// but has not been validated against the database - /// - Authenticated, - /// /// represents when the client has been authenticated by RCon /// and validated by the database /// @@ -86,6 +80,7 @@ namespace SharedLibraryCore.Database.Models { { "_reportCount", 0 } }; + CurrentAlias = CurrentAlias ?? new EFAlias(); } public override string ToString() @@ -410,7 +405,7 @@ namespace SharedLibraryCore.Database.Models public void OnConnect() { var loc = Utilities.CurrentLocalization.LocalizationIndex; - //#if !DEBUG +#if !DEBUG if (Name.Length < 3) { CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is too short"); @@ -435,7 +430,7 @@ namespace SharedLibraryCore.Database.Models } // reserved slots stuff - if ((CurrentServer.GetClientsAsList().Count(_client => !_client.IsPrivileged()) - CurrentServer.MaxClients) < CurrentServer.ServerConfig.ReservedSlotNumber && + if (CurrentServer.MaxClients - (CurrentServer.GetClientsAsList().Count(_client => !_client.IsPrivileged())) < CurrentServer.ServerConfig.ReservedSlotNumber && !this.IsPrivileged()) { CurrentServer.Logger.WriteDebug($"Kicking {this} their spot is reserved"); @@ -446,13 +441,34 @@ namespace SharedLibraryCore.Database.Models LastConnection = DateTime.UtcNow; Connections += 1; - //#endif +#endif + } + + public async Task OnDisconnect() + { + State = ClientState.Disconnecting; + TotalConnectionTime += ConnectionLength; + LastConnection = DateTime.UtcNow; + await CurrentServer.Manager.GetClientService().Update(this); } public async Task OnJoin(int ipAddress) { // todo: fix this up - CurrentAlias.IPAddress = IPAddress; + var existingAlias = AliasLink.Children + .FirstOrDefault(a => a.Name == Name && a.IPAddress == ipAddress); + + if (existingAlias == null) + { + CurrentServer.Logger.WriteDebug($"Client {this} has connected previously under a different ip/name"); + + CurrentAlias = new EFAlias() + { + IPAddress = ipAddress, + Name = Name + }; + } + await CurrentServer.Manager.GetClientService().Update(this); var loc = Utilities.CurrentLocalization.LocalizationIndex; @@ -477,9 +493,8 @@ namespace SharedLibraryCore.Database.Models CurrentServer.Logger.WriteInfo($"Banned client {this} trying to join..."); var autoKickClient = Utilities.IW4MAdminClient(CurrentServer); - // reban the "evading" guid - if (Level != Permission.Banned && + if (Level != Permission.Banned && currentBan.Type == Penalty.PenaltyType.Ban) { // hack: re apply the automated offense to the reban @@ -501,11 +516,7 @@ namespace SharedLibraryCore.Database.Models else { - //string formattedKick = String.Format( - // RconParser.GetCommandPrefixes().Kick, - // polledPlayer.ClientNumber, - // $"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})"); - //await this.ExecuteCommandAsync(formattedKick); + Kick($"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient); } } } diff --git a/SharedLibraryCore/RCon/Connection.cs b/SharedLibraryCore/RCon/Connection.cs index 50f886d59..af1989d85 100644 --- a/SharedLibraryCore/RCon/Connection.cs +++ b/SharedLibraryCore/RCon/Connection.cs @@ -106,11 +106,17 @@ namespace SharedLibraryCore.RCon try { response = await SendPayloadAsync(payload, waitForResponse); + + if (response.Length == 0) + { + throw new Exception(); + } + connectionState.OnComplete.Release(1); connectionState.ConnectionAttempts = 0; } - catch/* (Exception ex)*/ + catch { if (connectionState.ConnectionAttempts < StaticHelpers.AllowedConnectionFails) { diff --git a/SharedLibraryCore/Server.cs b/SharedLibraryCore/Server.cs index 53d3dbdb9..5d290debd 100644 --- a/SharedLibraryCore/Server.cs +++ b/SharedLibraryCore/Server.cs @@ -79,7 +79,7 @@ namespace SharedLibraryCore /// /// Client ID of player to be removed /// true if removal succeded, false otherwise - abstract public Task RemoveClient(int cNum); + abstract public Task OnClientDisconnected(EFClient client); ///