More work modifying client stuff

This commit is contained in:
RaidMax 2018-11-07 20:30:11 -06:00
parent ed83c4c011
commit 9bdd7d1b8a
14 changed files with 255 additions and 307 deletions

View File

@ -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<EFClient> ClientAuthenticationQueue;
private Dictionary<long, EFClient> AuthenticatedClients;
public ClientAuthentication()
{
ClientAuthenticationQueue = new Queue<EFClient>();
AuthenticatedClients = new Dictionary<long, EFClient>();
}
public void AuthenticateClients(IList<EFClient> 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<EFClient> 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);
}
}
}

View File

@ -144,7 +144,7 @@ namespace IW4MAdmin.Application.EventParsers
{ {
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Join, Type = GameEvent.EventType.PreConnect,
Data = logLine, Data = logLine,
Owner = server, Owner = server,
Origin = new EFClient() Origin = new EFClient()
@ -159,26 +159,26 @@ namespace IW4MAdmin.Application.EventParsers
} }
} }
//if (eventType == "Q") if (eventType == "Q")
//{ {
// var regexMatch = Regex.Match(logLine, @"^(Q;)(.{1,32});([0-9]+);(.*)$"); var regexMatch = Regex.Match(logLine, @"^(Q;)(.{1,32});([0-9]+);(.*)$");
// if (regexMatch.Success) if (regexMatch.Success)
// { {
// return new GameEvent() return new GameEvent()
// { {
// Type = GameEvent.EventType.Quit, Type = GameEvent.EventType.PreDisconnect,
// Data = logLine, Data = logLine,
// Owner = server, Owner = server,
// Origin = new Player() Origin = new EFClient()
// { {
// Name = regexMatch.Groups[4].ToString().StripColors(), Name = regexMatch.Groups[4].ToString().StripColors(),
// NetworkId = regexMatch.Groups[2].ToString().ConvertLong(), NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
// ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()), ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()),
// State = Player.ClientState.Connecting State = EFClient.ClientState.Disconnecting
// } }
// }; };
// } }
//} }
if (eventType.Contains("ExitLevel")) if (eventType.Contains("ExitLevel"))
{ {
@ -186,14 +186,8 @@ namespace IW4MAdmin.Application.EventParsers
{ {
Type = GameEvent.EventType.MapEnd, Type = GameEvent.EventType.MapEnd,
Data = lineSplit[0], Data = lineSplit[0],
Origin = new EFClient() Origin = Utilities.IW4MAdminClient(server),
{ Target = Utilities.IW4MAdminClient(server),
ClientId = 1
},
Target = new EFClient()
{
ClientId = 1
},
Owner = server Owner = server
}; };
} }

View File

@ -33,7 +33,7 @@ namespace IW4MAdmin.Application.EventParsers
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Join, Type = GameEvent.EventType.PreConnect,
Origin = new EFClient() Origin = new EFClient()
{ {
ClientId = 1 ClientId = 1

View File

@ -79,6 +79,7 @@ namespace IW4MAdmin.Application.IO
foreach (var ev in events) foreach (var ev in events)
{ {
Server.Manager.GetEventHandler().AddEvent(ev); Server.Manager.GetEventHandler().AddEvent(ev);
await ev.WaitAsync();
} }
PreviousFileSize = fileSize; PreviousFileSize = fileSize;

View File

@ -32,6 +32,7 @@ namespace IW4MAdmin
public override int GetHashCode() public override int GetHashCode()
{ {
// hack: my laziness
if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28965") if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28965")
{ {
return 886229536; return 886229536;
@ -56,16 +57,6 @@ namespace IW4MAdmin
return Id; 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) override public async Task OnClientConnected(EFClient clientFromLog)
{ {
Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved"); Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved");
@ -119,40 +110,49 @@ namespace IW4MAdmin
Clients[client.ClientNumber] = client; Clients[client.ClientNumber] = client;
client.OnConnect(); 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; 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) catch (Exception ex)
{ {
Logger.WriteError($"{loc["SERVER_ERROR_ADDPLAYER"]} {clientFromLog.Name}::{clientFromLog.NetworkId}"); Logger.WriteError($"{loc["SERVER_ERROR_ADDPLAYER"]} {clientFromLog}");
Logger.WriteDebug(ex.Message); Logger.WriteError(ex.GetExceptionInfo());
Logger.WriteDebug(ex.StackTrace);
} }
} }
//Remove player by CLIENT NUMBER override public async Task OnClientDisconnected(EFClient client)
override public async Task RemoveClient(int cNum)
{ {
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 Manager.GetEventHandler().AddEvent(e);
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;
}
}
} }
public override async Task ExecuteEvent(GameEvent E) public override async Task ExecuteEvent(GameEvent E)
@ -218,27 +218,34 @@ namespace IW4MAdmin
/// <returns></returns> /// <returns></returns>
override protected async Task<bool> ProcessEvent(GameEvent E) override protected async Task<bool> ProcessEvent(GameEvent E)
{ {
if (E.Type == GameEvent.EventType.Connect) if (E.Type == GameEvent.EventType.PreConnect)
{ {
E.Origin.State = EFClient.ClientState.Authenticated; bool clientExists = GetClientsAsList().Exists(_client => _client.NetworkId.Equals(E.Origin));
await OnClientConnected(E.Origin);
ChatHistory.Add(new ChatInfo() if (!clientExists)
{ {
Name = E.Origin.Name, #if DEBUG == true
Message = "CONNECTED", Logger.WriteDebug($"Begin PreConnect for {E.Origin}");
Time = DateTime.UtcNow #endif
}); await OnClientConnected(E.Origin);
if (E.Origin.Level > EFClient.Permission.Moderator) ChatHistory.Add(new ChatInfo()
{ {
E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count)); 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) else
{ {
await OnClientJoined(E.Origin); return false;
}
} }
else if (E.Type == GameEvent.EventType.Flag) else if (E.Type == GameEvent.EventType.Flag)
@ -303,13 +310,9 @@ namespace IW4MAdmin
else if (E.Type == GameEvent.EventType.Quit) 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 && 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)
{ {
var e = new GameEvent() var e = new GameEvent()
{ {
@ -321,29 +324,45 @@ namespace IW4MAdmin
Manager.GetEventHandler().AddEvent(e); Manager.GetEventHandler().AddEvent(e);
} }
else if (origin != null && else
origin.State != EFClient.ClientState.Connected)
{ {
await RemoveClient(origin.ClientNumber); return false;
} }
} }
else if (E.Type == GameEvent.EventType.Disconnect) else if (E.Type == GameEvent.EventType.PreDisconnect)
{ {
ChatHistory.Add(new ChatInfo() // predisconnect comes from minimal rcon polled players and minimal log players
{ // so we need to disconnect the "full" version of the client
Name = E.Origin.Name, var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin));
Message = "DISCONNECTED",
Time = DateTime.UtcNow
});
var currentState = E.Origin.State; if (client != null)
await RemoveClient(E.Origin.ClientNumber);
if (currentState != EFClient.ClientState.Connected)
{ {
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) if (E.Type == GameEvent.EventType.Say)
@ -440,6 +459,24 @@ namespace IW4MAdmin
return true; 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;
}
/// <summary> /// <summary>
/// lists the connecting and disconnecting clients via RCon response /// lists the connecting and disconnecting clients via RCon response
/// array index 0 = connecting clients /// array index 0 = connecting clients
@ -471,9 +508,15 @@ namespace IW4MAdmin
} }
var disconnectingClients = currentClients.Except(polledClients); 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<EFClient>[] { connectingClients.ToList(), disconnectingClients.ToList() }; return new List<EFClient>[]
{
connectingClients.ToList(),
disconnectingClients.ToList(),
updatedClients.ToList()
};
} }
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
@ -484,21 +527,30 @@ namespace IW4MAdmin
{ {
try try
{ {
#region SHUTDOWN
if (Manager.ShutdownRequested()) if (Manager.ShutdownRequested())
{ {
// todo: fix up disconnect foreach (var client in GetClientsAsList())
//for (int i = 0; i < EFClients.Count; i++) {
// await RemoveClient(i); 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) foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
{ {
await plugin.OnUnloadAsync(); await plugin.OnUnloadAsync();
} }
}
// only check every 2 minutes if the server doesn't seem to be responding return true;
/* if ((DateTime.Now - LastPoll).TotalMinutes < 0.5 && ConnectionErrors >= 1) }
return true;*/ #endregion
try try
{ {
@ -514,7 +566,7 @@ namespace IW4MAdmin
var e = new GameEvent() var e = new GameEvent()
{ {
Type = GameEvent.EventType.Disconnect, Type = GameEvent.EventType.PreDisconnect,
Origin = disconnectingClient, Origin = disconnectingClient,
Owner = this Owner = this
}; };
@ -531,16 +583,9 @@ namespace IW4MAdmin
// this are our new connecting clients // this are our new connecting clients
foreach (var client in polledClients[0]) 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() var e = new GameEvent()
{ {
Type = GameEvent.EventType.Connect, Type = GameEvent.EventType.PreConnect,
Origin = client, Origin = client,
Owner = this Owner = this
}; };
@ -552,11 +597,29 @@ namespace IW4MAdmin
// wait for all the connect tasks to finish // wait for all the connect tasks to finish
await Task.WhenAll(waiterList.Select(e => e.WaitAsync(10 * 1000))); 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) if (ConnectionErrors > 0)
{ {
Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}"); Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}");
Throttled = false; Throttled = false;
} }
ConnectionErrors = 0; ConnectionErrors = 0;
LastPoll = DateTime.Now; LastPoll = DateTime.Now;
} }
@ -576,20 +639,6 @@ namespace IW4MAdmin
LastMessage = DateTime.Now - start; LastMessage = DateTime.Now - start;
lastCount = DateTime.Now; 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 // update the player history
if ((lastCount - playerCountStart).TotalMinutes >= SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval) if ((lastCount - playerCountStart).TotalMinutes >= SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval)
{ {
@ -849,7 +898,7 @@ namespace IW4MAdmin
#endif #endif
#if DEBUG #if DEBUG
await Target.CurrentServer.RemoveClient(Target.ClientNumber); await Target.CurrentServer.OnClientDisconnected(Target);
#endif #endif
var newPenalty = new Penalty() var newPenalty = new Penalty()
@ -887,7 +936,7 @@ namespace IW4MAdmin
await Target.CurrentServer.ExecuteCommandAsync(formattedKick); await Target.CurrentServer.ExecuteCommandAsync(formattedKick);
} }
#else #else
await Target.CurrentServer.RemoveClient(Target.ClientNumber); await Target.CurrentServer.OnClientDisconnected(Target);
#endif #endif
Penalty newPenalty = new Penalty() 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"); 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); await Target.CurrentServer.ExecuteCommandAsync(formattedString);
#else #else
await Target.CurrentServer.RemoveClient(Target.ClientNumber); await Target.CurrentServer.OnClientDisconnected(Target);
#endif #endif
} }

View File

@ -85,29 +85,7 @@ namespace IW4MAdmin.Application
} }
try 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); await newEvent.Owner.ExecuteEvent(newEvent);

View File

@ -1,22 +1,26 @@
aniso8601==3.0.2 aniso8601==3.0.2
APScheduler==3.5.3
certifi==2018.10.15
chardet==3.0.4
click==6.7 click==6.7
Flask==1.0.2 Flask==1.0.2
Flask-JWT==0.3.2 Flask-JWT==0.3.2
Flask-JWT-Extended==3.8.1 Flask-JWT-Extended==3.8.1
Flask-RESTful==0.3.6 Flask-RESTful==0.3.6
idna==2.7
itsdangerous==0.24 itsdangerous==0.24
Jinja2==2.10 Jinja2==2.10
MarkupSafe==1.0 MarkupSafe==1.0
marshmallow==3.0.0b8 marshmallow==3.0.0b8
pip==9.0.3 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 psutil==5.4.8
pygal==2.4.0
PyJWT==1.4.2
pytz==2018.7
requests==2.20.0 requests==2.20.0
setuptools==40.5.0
six==1.11.0
timeago==1.0.8
tzlocal==1.5.1
urllib3==1.24 urllib3==1.24
Werkzeug==0.14.1

View File

@ -244,7 +244,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
{ {
int serverId = pl.CurrentServer.GetHashCode(); int serverId = pl.CurrentServer.GetHashCode();
if (!Servers.ContainsKey(serverId)) if (!Servers.ContainsKey(serverId))
{ {
Log.WriteError($"[Stats::AddPlayer] Server with id {serverId} could not be found"); Log.WriteError($"[Stats::AddPlayer] Server with id {serverId} could not be found");

View File

@ -41,13 +41,13 @@ namespace SharedLibraryCore.Database.Models
public virtual string Name public virtual string Name
{ {
get { return CurrentAlias.Name; } get { return CurrentAlias.Name; }
set { } set { CurrentAlias.Name = value; }
} }
[NotMapped] [NotMapped]
public virtual int IPAddress public virtual int IPAddress
{ {
get { return CurrentAlias.IPAddress; } get { return CurrentAlias.IPAddress; }
set { } set { CurrentAlias.IPAddress = value; }
} }
[NotMapped] [NotMapped]

View File

@ -1,8 +1,7 @@
using System; using SharedLibraryCore.Database.Models;
using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Objects;
namespace SharedLibraryCore namespace SharedLibraryCore
{ {
@ -74,6 +73,18 @@ namespace SharedLibraryCore
/// the current map changed /// the current map changed
/// </summary> /// </summary>
MapChange, MapChange,
/// <summary>
/// a client was detected as starting to connect
/// </summary>
PreConnect,
/// <summary>
/// a client was detecting as starting to disconnect
/// </summary>
PreDisconnect,
/// <summary>
/// a client's information was updated
/// </summary>
Update,
// events "generated" by clients // events "generated" by clients
/// <summary> /// <summary>
@ -159,7 +170,10 @@ namespace SharedLibraryCore
} }
static long NextEventId; static long NextEventId;
static long GetNextEventId() => Interlocked.Increment(ref NextEventId); static long GetNextEventId()
{
return Interlocked.Increment(ref NextEventId);
}
public GameEvent() public GameEvent()
{ {
@ -186,11 +200,14 @@ namespace SharedLibraryCore
/// asynchronously wait for GameEvent to be processed /// asynchronously wait for GameEvent to be processed
/// </summary> /// </summary>
/// <returns>waitable task </returns> /// <returns>waitable task </returns>
public Task<GameEvent> WaitAsync(int timeOut = int.MaxValue) => Task.Run(() => public Task<GameEvent> WaitAsync(int timeOut = int.MaxValue)
{ {
OnProcessed.Wait(timeOut); return Task.Run(() =>
return this; {
}); OnProcessed.Wait(timeOut);
return this;
});
}
/// <summary> /// <summary>
/// determine whether an event should be delayed or not /// determine whether an event should be delayed or not

View File

@ -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
{
/// <summary>
/// request authentication when a client join event
/// occurs in the log, as no IP is given
/// </summary>
/// <param name="client">client that has joined from the log</param>
void RequestClientAuthentication(EFClient client);
/// <summary>
/// get all clients that have been authenticated by the status poll
/// </summary>
/// <returns>list of all authenticated clients</returns>
IList<EFClient> GetAuthenticatedClients();
/// <summary>
/// authenticate a list of clients from status poll
/// </summary>
/// <param name="clients">list of clients to authenticate</param>
void AuthenticateClients(IList<EFClient> clients);
}
}

View File

@ -1,5 +1,4 @@
using SharedLibraryCore.Database.Models; using SharedLibraryCore.Objects;
using SharedLibraryCore.Objects;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
@ -18,11 +17,6 @@ namespace SharedLibraryCore.Database.Models
/// </summary> /// </summary>
Connecting, Connecting,
/// <summary> /// <summary>
/// represents when the client has been parsed by RCon,
/// but has not been validated against the database
/// </summary>
Authenticated,
/// <summary>
/// represents when the client has been authenticated by RCon /// represents when the client has been authenticated by RCon
/// and validated by the database /// and validated by the database
/// </summary> /// </summary>
@ -86,6 +80,7 @@ namespace SharedLibraryCore.Database.Models
{ {
{ "_reportCount", 0 } { "_reportCount", 0 }
}; };
CurrentAlias = CurrentAlias ?? new EFAlias();
} }
public override string ToString() public override string ToString()
@ -410,7 +405,7 @@ namespace SharedLibraryCore.Database.Models
public void OnConnect() public void OnConnect()
{ {
var loc = Utilities.CurrentLocalization.LocalizationIndex; var loc = Utilities.CurrentLocalization.LocalizationIndex;
//#if !DEBUG #if !DEBUG
if (Name.Length < 3) if (Name.Length < 3)
{ {
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is too short"); CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is too short");
@ -435,7 +430,7 @@ namespace SharedLibraryCore.Database.Models
} }
// reserved slots stuff // 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()) !this.IsPrivileged())
{ {
CurrentServer.Logger.WriteDebug($"Kicking {this} their spot is reserved"); CurrentServer.Logger.WriteDebug($"Kicking {this} their spot is reserved");
@ -446,13 +441,34 @@ namespace SharedLibraryCore.Database.Models
LastConnection = DateTime.UtcNow; LastConnection = DateTime.UtcNow;
Connections += 1; 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) public async Task OnJoin(int ipAddress)
{ {
// todo: fix this up // 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); await CurrentServer.Manager.GetClientService().Update(this);
var loc = Utilities.CurrentLocalization.LocalizationIndex; var loc = Utilities.CurrentLocalization.LocalizationIndex;
@ -477,9 +493,8 @@ namespace SharedLibraryCore.Database.Models
CurrentServer.Logger.WriteInfo($"Banned client {this} trying to join..."); CurrentServer.Logger.WriteInfo($"Banned client {this} trying to join...");
var autoKickClient = Utilities.IW4MAdminClient(CurrentServer); var autoKickClient = Utilities.IW4MAdminClient(CurrentServer);
// reban the "evading" guid // reban the "evading" guid
if (Level != Permission.Banned && if (Level != Permission.Banned &&
currentBan.Type == Penalty.PenaltyType.Ban) currentBan.Type == Penalty.PenaltyType.Ban)
{ {
// hack: re apply the automated offense to the reban // hack: re apply the automated offense to the reban
@ -501,11 +516,7 @@ namespace SharedLibraryCore.Database.Models
else else
{ {
//string formattedKick = String.Format( Kick($"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
// RconParser.GetCommandPrefixes().Kick,
// polledPlayer.ClientNumber,
// $"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})");
//await this.ExecuteCommandAsync(formattedKick);
} }
} }
} }

View File

@ -106,11 +106,17 @@ namespace SharedLibraryCore.RCon
try try
{ {
response = await SendPayloadAsync(payload, waitForResponse); response = await SendPayloadAsync(payload, waitForResponse);
if (response.Length == 0)
{
throw new Exception();
}
connectionState.OnComplete.Release(1); connectionState.OnComplete.Release(1);
connectionState.ConnectionAttempts = 0; connectionState.ConnectionAttempts = 0;
} }
catch/* (Exception ex)*/ catch
{ {
if (connectionState.ConnectionAttempts < StaticHelpers.AllowedConnectionFails) if (connectionState.ConnectionAttempts < StaticHelpers.AllowedConnectionFails)
{ {

View File

@ -79,7 +79,7 @@ namespace SharedLibraryCore
/// </summary> /// </summary>
/// <param name="cNum">Client ID of player to be removed</param> /// <param name="cNum">Client ID of player to be removed</param>
/// <returns>true if removal succeded, false otherwise</returns> /// <returns>true if removal succeded, false otherwise</returns>
abstract public Task RemoveClient(int cNum); abstract public Task OnClientDisconnected(EFClient client);
/// <summary> /// <summary>