fix alias command sending message to origin instead of target
(hopefully) fix an issue with banned players causing exception if they create events before they are kicked out fix issues with sometimes wrong error message for timeout show most recent IP address at top of alias list optimization to some sql queries
This commit is contained in:
parent
cb9119ac58
commit
161b27e2f2
@ -33,8 +33,6 @@ namespace IW4MAdmin.Application
|
|||||||
public ILogger Logger => GetLogger(0);
|
public ILogger Logger => GetLogger(0);
|
||||||
public bool Running { get; private set; }
|
public bool Running { get; private set; }
|
||||||
public bool IsInitialized { get; private set; }
|
public bool IsInitialized { get; private set; }
|
||||||
// expose the event handler so we can execute the events
|
|
||||||
public OnServerEventEventHandler OnServerEvent { get; set; }
|
|
||||||
public DateTime StartTime { get; private set; }
|
public DateTime StartTime { get; private set; }
|
||||||
public string Version => Assembly.GetEntryAssembly().GetName().Version.ToString();
|
public string Version => Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||||
|
|
||||||
@ -73,21 +71,19 @@ namespace IW4MAdmin.Application
|
|||||||
PageList = new PageList();
|
PageList = new PageList();
|
||||||
AdditionalEventParsers = new List<IEventParser>();
|
AdditionalEventParsers = new List<IEventParser>();
|
||||||
AdditionalRConParsers = new List<IRConParser>();
|
AdditionalRConParsers = new List<IRConParser>();
|
||||||
OnServerEvent += OnGameEvent;
|
//OnServerEvent += OnGameEvent;
|
||||||
OnServerEvent += EventApi.OnGameEvent;
|
//OnServerEvent += EventApi.OnGameEvent;
|
||||||
TokenAuthenticator = new TokenAuthentication();
|
TokenAuthenticator = new TokenAuthentication();
|
||||||
_metaService = new MetaService();
|
_metaService = new MetaService();
|
||||||
_tokenSource = new CancellationTokenSource();
|
_tokenSource = new CancellationTokenSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnGameEvent(object sender, GameEventArgs args)
|
public async Task ExecuteEvent(GameEvent newEvent)
|
||||||
{
|
{
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
Logger.WriteDebug($"Entering event process for {args.Event.Id}");
|
Logger.WriteDebug($"Entering event process for {newEvent.Id}");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var newEvent = args.Event;
|
|
||||||
|
|
||||||
// the event has failed already
|
// the event has failed already
|
||||||
if (newEvent.Failed)
|
if (newEvent.Failed)
|
||||||
{
|
{
|
||||||
@ -96,12 +92,11 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await newEvent.Owner.EventProcessing.WaitAsync(CancellationToken);
|
|
||||||
await newEvent.Owner.ExecuteEvent(newEvent);
|
await newEvent.Owner.ExecuteEvent(newEvent);
|
||||||
|
|
||||||
// save the event info to the database
|
// save the event info to the database
|
||||||
var changeHistorySvc = new ChangeHistoryService();
|
var changeHistorySvc = new ChangeHistoryService();
|
||||||
await changeHistorySvc.Add(args.Event);
|
await changeHistorySvc.Add(newEvent);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.WriteDebug($"Processed event with id {newEvent.Id}");
|
Logger.WriteDebug($"Processed event with id {newEvent.Id}");
|
||||||
@ -145,22 +140,12 @@ namespace IW4MAdmin.Application
|
|||||||
Logger.WriteDebug(ex.GetExceptionInfo());
|
Logger.WriteDebug(ex.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (newEvent.Owner.EventProcessing.CurrentCount == 0)
|
|
||||||
{
|
|
||||||
newEvent.Owner.EventProcessing.Release(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG == true
|
|
||||||
Logger.WriteDebug($"Exiting event process for {args.Event.Id}");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
|
|
||||||
// tell anyone waiting for the output that we're done
|
// tell anyone waiting for the output that we're done
|
||||||
newEvent.OnProcessed.Set();
|
newEvent.Complete();
|
||||||
|
#if DEBUG == true
|
||||||
|
Logger.WriteDebug($"Exiting event process for {newEvent.Id}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<Server> GetServers()
|
public IList<Server> GetServers()
|
||||||
|
@ -256,6 +256,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
// this is a custom event printed out by _customcallbacks.gsc (used for anticheat)
|
// this is a custom event printed out by _customcallbacks.gsc (used for anticheat)
|
||||||
if (eventType == "ScriptKill")
|
if (eventType == "ScriptKill")
|
||||||
{
|
{
|
||||||
|
|
||||||
long originId = lineSplit[1].ConvertGuidToLong(1);
|
long originId = lineSplit[1].ConvertGuidToLong(1);
|
||||||
long targetId = lineSplit[2].ConvertGuidToLong(1);
|
long targetId = lineSplit[2].ConvertGuidToLong(1);
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using SharedLibraryCore;
|
using IW4MAdmin.Application.Misc;
|
||||||
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Events;
|
using SharedLibraryCore.Events;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@ -9,7 +11,11 @@ namespace IW4MAdmin.Application
|
|||||||
class GameEventHandler : IEventHandler
|
class GameEventHandler : IEventHandler
|
||||||
{
|
{
|
||||||
readonly ApplicationManager Manager;
|
readonly ApplicationManager Manager;
|
||||||
private static GameEvent.EventType[] overrideEvents = new[]
|
private readonly EventProfiler _profiler;
|
||||||
|
private delegate void GameEventAddedEventHandler(object sender, GameEventArgs args);
|
||||||
|
private event GameEventAddedEventHandler GameEventAdded;
|
||||||
|
|
||||||
|
private static readonly GameEvent.EventType[] overrideEvents = new[]
|
||||||
{
|
{
|
||||||
GameEvent.EventType.Connect,
|
GameEvent.EventType.Connect,
|
||||||
GameEvent.EventType.Disconnect,
|
GameEvent.EventType.Disconnect,
|
||||||
@ -20,6 +26,17 @@ namespace IW4MAdmin.Application
|
|||||||
public GameEventHandler(IManager mgr)
|
public GameEventHandler(IManager mgr)
|
||||||
{
|
{
|
||||||
Manager = (ApplicationManager)mgr;
|
Manager = (ApplicationManager)mgr;
|
||||||
|
_profiler = new EventProfiler(mgr.GetLogger(0));
|
||||||
|
GameEventAdded += GameEventHandler_GameEventAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void GameEventHandler_GameEventAdded(object sender, GameEventArgs args)
|
||||||
|
{
|
||||||
|
var start = DateTime.Now;
|
||||||
|
await Manager.ExecuteEvent(args.Event);
|
||||||
|
#if DEBUG
|
||||||
|
_profiler.Profile(start, DateTime.Now, args.Event);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddEvent(GameEvent gameEvent)
|
public void AddEvent(GameEvent gameEvent)
|
||||||
@ -35,7 +52,7 @@ namespace IW4MAdmin.Application
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
gameEvent.Owner.Logger.WriteDebug($"Adding event with id {gameEvent.Id}");
|
gameEvent.Owner.Logger.WriteDebug($"Adding event with id {gameEvent.Id}");
|
||||||
#endif
|
#endif
|
||||||
Manager.OnServerEvent?.Invoke(gameEvent.Owner, new GameEventArgs(null, false, gameEvent));
|
GameEventAdded?.Invoke(this, new GameEventArgs(null, false, gameEvent));
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
else
|
else
|
||||||
|
@ -76,7 +76,6 @@ namespace IW4MAdmin.Application.IO
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
_server.Logger.WriteVerbose(gameEvent.Data);
|
_server.Logger.WriteVerbose(gameEvent.Data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// we don't want to add the event if ignoreBots is on and the event comes from a bot
|
// we don't want to add the event if ignoreBots is on and the event comes from a bot
|
||||||
if (!_ignoreBots || (_ignoreBots && !((gameEvent.Origin?.IsBot ?? false) || (gameEvent.Target?.IsBot ?? false))))
|
if (!_ignoreBots || (_ignoreBots && !((gameEvent.Origin?.IsBot ?? false) || (gameEvent.Target?.IsBot ?? false))))
|
||||||
{
|
{
|
||||||
@ -103,11 +102,6 @@ namespace IW4MAdmin.Application.IO
|
|||||||
}
|
}
|
||||||
|
|
||||||
_server.Manager.GetEventHandler().AddEvent(gameEvent);
|
_server.Manager.GetEventHandler().AddEvent(gameEvent);
|
||||||
|
|
||||||
if (gameEvent.IsBlocking)
|
|
||||||
{
|
|
||||||
await gameEvent.WaitAsync(Utilities.DefaultCommandTimeout, _server.Manager.CancellationToken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
override public async Task OnClientConnected(EFClient clientFromLog)
|
override public async Task<EFClient> OnClientConnected(EFClient clientFromLog)
|
||||||
{
|
{
|
||||||
Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved");
|
Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved");
|
||||||
|
|
||||||
@ -57,6 +57,7 @@ namespace IW4MAdmin
|
|||||||
Logger.WriteInfo($"Client {client} connected...");
|
Logger.WriteInfo($"Client {client} connected...");
|
||||||
|
|
||||||
// Do the player specific stuff
|
// Do the player specific stuff
|
||||||
|
client.ProcessingEvent = clientFromLog.ProcessingEvent;
|
||||||
client.ClientNumber = clientFromLog.ClientNumber;
|
client.ClientNumber = clientFromLog.ClientNumber;
|
||||||
client.Score = clientFromLog.Score;
|
client.Score = clientFromLog.Score;
|
||||||
client.Ping = clientFromLog.Ping;
|
client.Ping = clientFromLog.Ping;
|
||||||
@ -73,9 +74,8 @@ namespace IW4MAdmin
|
|||||||
Type = GameEvent.EventType.Connect
|
Type = GameEvent.EventType.Connect
|
||||||
};
|
};
|
||||||
|
|
||||||
await client.OnJoin(client.IPAddress);
|
|
||||||
client.State = ClientState.Connected;
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
override public async Task OnClientDisconnected(EFClient client)
|
override public async Task OnClientDisconnected(EFClient client)
|
||||||
@ -103,55 +103,85 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
public override async Task ExecuteEvent(GameEvent E)
|
public override async Task ExecuteEvent(GameEvent E)
|
||||||
{
|
{
|
||||||
bool canExecuteCommand = true;
|
if (E == null)
|
||||||
|
|
||||||
if (!await ProcessEvent(E))
|
|
||||||
{
|
{
|
||||||
|
Logger.WriteError("Received NULL event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command C = null;
|
if (E.IsBlocking)
|
||||||
if (E.Type == GameEvent.EventType.Command)
|
|
||||||
{
|
{
|
||||||
try
|
await E.Origin?.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canExecuteCommand = true;
|
||||||
|
Exception lastException = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!await ProcessEvent(E))
|
||||||
{
|
{
|
||||||
C = await SharedLibraryCore.Commands.CommandProcessing.ValidateCommand(E);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (CommandException e)
|
Command C = null;
|
||||||
|
if (E.Type == GameEvent.EventType.Command)
|
||||||
{
|
{
|
||||||
Logger.WriteInfo(e.Message);
|
try
|
||||||
|
{
|
||||||
|
C = await SharedLibraryCore.Commands.CommandProcessing.ValidateCommand(E);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (CommandException e)
|
||||||
|
{
|
||||||
|
Logger.WriteInfo(e.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (C != null)
|
||||||
|
{
|
||||||
|
E.Extra = C;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (C != null)
|
foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
|
||||||
{
|
{
|
||||||
E.Extra = C;
|
try
|
||||||
|
{
|
||||||
|
await plugin.OnEventAsync(E, this);
|
||||||
|
}
|
||||||
|
catch (AuthorizationException e)
|
||||||
|
{
|
||||||
|
E.Origin.Tell($"{loc["COMMAND_NOTAUTHORIZED"]} - {e.Message}");
|
||||||
|
canExecuteCommand = false;
|
||||||
|
}
|
||||||
|
catch (Exception Except)
|
||||||
|
{
|
||||||
|
Logger.WriteError($"{loc["SERVER_PLUGIN_ERROR"]} [{plugin.Name}]");
|
||||||
|
Logger.WriteDebug(Except.GetExceptionInfo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack: this prevents commands from getting executing that 'shouldn't' be
|
||||||
|
if (E.Type == GameEvent.EventType.Command && E.Extra is Command command &&
|
||||||
|
(canExecuteCommand || E.Origin?.Level == Permission.Console))
|
||||||
|
{
|
||||||
|
await command.ExecuteAsync(E);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
try
|
lastException = e;
|
||||||
{
|
|
||||||
await plugin.OnEventAsync(E, this);
|
|
||||||
}
|
|
||||||
catch (AuthorizationException e)
|
|
||||||
{
|
|
||||||
E.Origin.Tell($"{loc["COMMAND_NOTAUTHORIZED"]} - {e.Message}");
|
|
||||||
canExecuteCommand = false;
|
|
||||||
}
|
|
||||||
catch (Exception Except)
|
|
||||||
{
|
|
||||||
Logger.WriteError($"{loc["SERVER_PLUGIN_ERROR"]} [{plugin.Name}]");
|
|
||||||
Logger.WriteDebug(Except.GetExceptionInfo());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hack: this prevents commands from getting executing that 'shouldn't' be
|
finally
|
||||||
if (E.Type == GameEvent.EventType.Command && E.Extra is Command command &&
|
|
||||||
(canExecuteCommand || E.Origin?.Level == Permission.Console))
|
|
||||||
{
|
{
|
||||||
await command.ExecuteAsync(E);
|
E.Origin?.Unlock();
|
||||||
|
|
||||||
|
if (lastException != null)
|
||||||
|
{
|
||||||
|
throw lastException;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +225,25 @@ namespace IW4MAdmin
|
|||||||
await Manager.GetClientService().UpdateLevel(newPermission, E.Target, E.Origin);
|
await Manager.GetClientService().UpdateLevel(newPermission, E.Target, E.Origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (E.Type == GameEvent.EventType.Connect)
|
||||||
|
{
|
||||||
|
if (E.Origin.State != ClientState.Connected)
|
||||||
|
{
|
||||||
|
E.Origin.State = ClientState.Connected;
|
||||||
|
E.Origin.LastConnection = DateTime.UtcNow;
|
||||||
|
E.Origin.Connections += 1;
|
||||||
|
|
||||||
|
ChatHistory.Add(new ChatInfo()
|
||||||
|
{
|
||||||
|
Name = E.Origin.Name,
|
||||||
|
Message = "CONNECTED",
|
||||||
|
Time = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
|
||||||
|
await E.Origin.OnJoin(E.Origin.IPAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (E.Type == GameEvent.EventType.PreConnect)
|
else if (E.Type == GameEvent.EventType.PreConnect)
|
||||||
{
|
{
|
||||||
// we don't want to track bots in the database at all if ignore bots is requested
|
// we don't want to track bots in the database at all if ignore bots is requested
|
||||||
@ -230,7 +279,8 @@ namespace IW4MAdmin
|
|||||||
Clients[E.Origin.ClientNumber] = E.Origin;
|
Clients[E.Origin.ClientNumber] = E.Origin;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await OnClientConnected(E.Origin);
|
E.Origin = await OnClientConnected(E.Origin);
|
||||||
|
E.Target = E.Origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -242,13 +292,6 @@ namespace IW4MAdmin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatHistory.Add(new ChatInfo()
|
|
||||||
{
|
|
||||||
Name = E.Origin.Name,
|
|
||||||
Message = "CONNECTED",
|
|
||||||
Time = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
|
|
||||||
if (E.Origin.Level > EFClient.Permission.Moderator)
|
if (E.Origin.Level > EFClient.Permission.Moderator)
|
||||||
{
|
{
|
||||||
E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
|
E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
|
||||||
@ -624,7 +667,6 @@ namespace IW4MAdmin
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
var polledClients = await PollPlayersAsync();
|
var polledClients = await PollPlayersAsync();
|
||||||
var waiterList = new List<GameEvent>();
|
|
||||||
|
|
||||||
foreach (var disconnectingClient in polledClients[1])
|
foreach (var disconnectingClient in polledClients[1])
|
||||||
{
|
{
|
||||||
@ -641,18 +683,9 @@ namespace IW4MAdmin
|
|||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
// wait until the disconnect event is complete
|
await e.WaitAsync(Utilities.DefaultCommandTimeout, Manager.CancellationToken);
|
||||||
// because we don't want to try to fill up a slot that's not empty yet
|
|
||||||
waiterList.Add(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for all the disconnect tasks to finish
|
|
||||||
foreach (var waiter in waiterList)
|
|
||||||
{
|
|
||||||
waiter.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
waiterList.Clear();
|
|
||||||
// this are our new connecting clients
|
// this are our new connecting clients
|
||||||
foreach (var client in polledClients[0])
|
foreach (var client in polledClients[0])
|
||||||
{
|
{
|
||||||
@ -671,16 +704,9 @@ namespace IW4MAdmin
|
|||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
waiterList.Add(e);
|
await e.WaitAsync(Utilities.DefaultCommandTimeout, Manager.CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for all the connect tasks to finish
|
|
||||||
foreach (var waiter in waiterList)
|
|
||||||
{
|
|
||||||
waiter.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
waiterList.Clear();
|
|
||||||
// these are the clients that have updated
|
// these are the clients that have updated
|
||||||
foreach (var client in polledClients[2])
|
foreach (var client in polledClients[2])
|
||||||
{
|
{
|
||||||
@ -692,12 +718,6 @@ namespace IW4MAdmin
|
|||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
waiterList.Add(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var waiter in waiterList)
|
|
||||||
{
|
|
||||||
waiter.Wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConnectionErrors > 0)
|
if (ConnectionErrors > 0)
|
||||||
|
63
Application/Misc/EventProfiler.cs
Normal file
63
Application/Misc/EventProfiler.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Misc
|
||||||
|
{
|
||||||
|
internal class EventPerformance
|
||||||
|
{
|
||||||
|
public long ExecutionTime { get; set; }
|
||||||
|
public GameEvent Event { get; set; }
|
||||||
|
public string EventInfo => $"{Event.Type}, {Event.FailReason}, {Event.IsBlocking}, {Event.Data}, {Event.Message}, {Event.Extra}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DuplicateKeyComparer<TKey> : IComparer<TKey> where TKey : IComparable
|
||||||
|
{
|
||||||
|
public int Compare(TKey x, TKey y)
|
||||||
|
{
|
||||||
|
int result = x.CompareTo(y);
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class EventProfiler
|
||||||
|
{
|
||||||
|
public double AverageEventTime { get; private set; }
|
||||||
|
public double MaxEventTime => Events.Values.Last().ExecutionTime;
|
||||||
|
public double MinEventTime => Events.Values[0].ExecutionTime;
|
||||||
|
public int TotalEventCount => Events.Count;
|
||||||
|
public SortedList<long, EventPerformance> Events { get; private set; } = new SortedList<long, EventPerformance>(new DuplicateKeyComparer<long>());
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public EventProfiler(ILogger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Profile(DateTime start, DateTime end, GameEvent gameEvent)
|
||||||
|
{
|
||||||
|
_logger.WriteDebug($"Starting profile of event {gameEvent.Id}");
|
||||||
|
long executionTime = (long)Math.Round((end - start).TotalMilliseconds);
|
||||||
|
|
||||||
|
var perf = new EventPerformance()
|
||||||
|
{
|
||||||
|
Event = gameEvent,
|
||||||
|
ExecutionTime = executionTime
|
||||||
|
};
|
||||||
|
|
||||||
|
lock (Events)
|
||||||
|
{
|
||||||
|
Events.Add(executionTime, perf);
|
||||||
|
}
|
||||||
|
|
||||||
|
AverageEventTime = (AverageEventTime * (TotalEventCount - 1) + executionTime) / TotalEventCount;
|
||||||
|
_logger.WriteDebug($"Finished profile of event {gameEvent.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application
|
namespace IW4MAdmin.Application
|
||||||
{
|
{
|
||||||
@ -20,16 +19,21 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
readonly string FileName;
|
readonly string FileName;
|
||||||
readonly SemaphoreSlim OnLogWriting;
|
readonly ReaderWriterLockSlim WritingLock;
|
||||||
static readonly short MAX_LOG_FILES = 10;
|
static readonly short MAX_LOG_FILES = 10;
|
||||||
|
|
||||||
public Logger(string fn)
|
public Logger(string fn)
|
||||||
{
|
{
|
||||||
FileName = Path.Join(Utilities.OperatingDirectory, "Log", $"{fn}.log");
|
FileName = Path.Join(Utilities.OperatingDirectory, "Log", $"{fn}.log");
|
||||||
OnLogWriting = new SemaphoreSlim(1, 1);
|
WritingLock = new ReaderWriterLockSlim();
|
||||||
RotateLogs();
|
RotateLogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~Logger()
|
||||||
|
{
|
||||||
|
WritingLock.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// rotates logs when log is initialized
|
/// rotates logs when log is initialized
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -56,7 +60,7 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
void Write(string msg, LogType type)
|
void Write(string msg, LogType type)
|
||||||
{
|
{
|
||||||
OnLogWriting.Wait();
|
WritingLock.EnterWriteLock();
|
||||||
|
|
||||||
string stringType = type.ToString();
|
string stringType = type.ToString();
|
||||||
msg = msg.StripColors();
|
msg = msg.StripColors();
|
||||||
@ -74,7 +78,7 @@ namespace IW4MAdmin.Application
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
// lets keep it simple and dispose of everything quickly as logging wont be that much (relatively)
|
// lets keep it simple and dispose of everything quickly as logging wont be that much (relatively)
|
||||||
Console.WriteLine(LogLine);
|
Console.WriteLine(LogLine);
|
||||||
File.AppendAllText(FileName, $"{LogLine}{Environment.NewLine}");
|
//File.AppendAllText(FileName, $"{LogLine}{Environment.NewLine}");
|
||||||
//Debug.WriteLine(msg);
|
//Debug.WriteLine(msg);
|
||||||
#else
|
#else
|
||||||
if (type == LogType.Error || type == LogType.Verbose)
|
if (type == LogType.Error || type == LogType.Verbose)
|
||||||
@ -91,7 +95,7 @@ namespace IW4MAdmin.Application
|
|||||||
Console.WriteLine(ex.GetExceptionInfo());
|
Console.WriteLine(ex.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
OnLogWriting.Release(1);
|
WritingLock.ExitWriteLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteVerbose(string msg)
|
public void WriteVerbose(string msg)
|
||||||
|
@ -38,7 +38,7 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Configuration.Status.Pattern = @"^ *([0-9]+) +-?([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$";
|
Configuration.Status.Pattern = @"^ *([0-9]+) +-?([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}|loopback|unknown) +(-*[0-9]+) +([0-9]+) *$";
|
||||||
Configuration.Status.AddMapping(ParserRegex.GroupType.RConClientNumber, 1);
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConClientNumber, 1);
|
||||||
Configuration.Status.AddMapping(ParserRegex.GroupType.RConScore, 2);
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConScore, 2);
|
||||||
Configuration.Status.AddMapping(ParserRegex.GroupType.RConPing, 3);
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConPing, 3);
|
||||||
|
@ -9,4 +9,4 @@ pip==10.0.1
|
|||||||
pytz==2018.9
|
pytz==2018.9
|
||||||
setuptools==39.0.1
|
setuptools==39.0.1
|
||||||
six==1.12.0
|
six==1.12.0
|
||||||
Werkzeug==0.15.2
|
Werkzeug==0.16.0
|
||||||
|
@ -6,6 +6,7 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Helpers
|
namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||||
{
|
{
|
||||||
@ -16,6 +17,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
public EFServer Server { get; private set; }
|
public EFServer Server { get; private set; }
|
||||||
private readonly Server _server;
|
private readonly Server _server;
|
||||||
public bool IsTeamBased { get; set; }
|
public bool IsTeamBased { get; set; }
|
||||||
|
public SemaphoreSlim OnSaving { get; private set; }
|
||||||
|
|
||||||
public ServerStats(EFServer sv, EFServerStatistics st, Server server)
|
public ServerStats(EFServer sv, EFServerStatistics st, Server server)
|
||||||
{
|
{
|
||||||
@ -23,6 +25,12 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
ServerStatistics = st;
|
ServerStatistics = st;
|
||||||
Server = sv;
|
Server = sv;
|
||||||
_server = server;
|
_server = server;
|
||||||
|
OnSaving = new SemaphoreSlim(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ServerStats()
|
||||||
|
{
|
||||||
|
OnSaving.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int TeamCount(IW4Info.Team teamName)
|
public int TeamCount(IW4Info.Team teamName)
|
||||||
|
@ -410,6 +410,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
Vector3 vDeathOrigin = null;
|
Vector3 vDeathOrigin = null;
|
||||||
Vector3 vKillOrigin = null;
|
Vector3 vKillOrigin = null;
|
||||||
Vector3 vViewAngles = null;
|
Vector3 vViewAngles = null;
|
||||||
|
var snapshotAngles = new List<Vector3>();
|
||||||
SemaphoreSlim waiter = null;
|
SemaphoreSlim waiter = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -419,20 +420,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
vDeathOrigin = Vector3.Parse(deathOrigin);
|
vDeathOrigin = Vector3.Parse(deathOrigin);
|
||||||
vKillOrigin = Vector3.Parse(killOrigin);
|
vKillOrigin = Vector3.Parse(killOrigin);
|
||||||
vViewAngles = Vector3.Parse(viewAngles).FixIW4Angles();
|
vViewAngles = Vector3.Parse(viewAngles).FixIW4Angles();
|
||||||
}
|
|
||||||
|
|
||||||
catch (FormatException)
|
|
||||||
{
|
|
||||||
_log.WriteWarning("Could not parse kill or death origin or viewangle vectors");
|
|
||||||
_log.WriteDebug($"Kill - {killOrigin} Death - {deathOrigin} ViewAngle - {viewAngles}");
|
|
||||||
await AddStandardKill(attacker, victim);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var snapshotAngles = new List<Vector3>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (string angle in snapAngles.Split(':', StringSplitOptions.RemoveEmptyEntries))
|
foreach (string angle in snapAngles.Split(':', StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
snapshotAngles.Add(Vector3.Parse(angle).FixIW4Angles());
|
snapshotAngles.Add(Vector3.Parse(angle).FixIW4Angles());
|
||||||
@ -441,7 +429,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
catch (FormatException)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
_log.WriteWarning("Could not parse snapshot angles");
|
_log.WriteError("Could not parse vector data from hit");
|
||||||
|
_log.WriteDebug($"Kill - {killOrigin} Death - {deathOrigin} ViewAngle - {viewAngles} Snapshot - {string.Join(",", snapshotAngles.Select(_a => _a.ToString()))}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,7 +467,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
var clientStats = attacker.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
var clientStats = attacker.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
||||||
|
|
||||||
waiter = clientStats.ProcessingHit;
|
waiter = clientStats.ProcessingHit;
|
||||||
await waiter.WaitAsync();
|
await waiter.WaitAsync(Utilities.DefaultCommandTimeout, Plugin.ServerManager.CancellationToken);
|
||||||
|
|
||||||
// increment their hit count
|
// increment their hit count
|
||||||
if (hit.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
if (hit.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
||||||
@ -495,12 +484,31 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
if (Plugin.Config.Configuration().StoreClientKills)
|
if (Plugin.Config.Configuration().StoreClientKills)
|
||||||
{
|
{
|
||||||
var cache = _servers[serverId].HitCache;
|
var serverWaiter = _servers[serverId].OnSaving;
|
||||||
cache.Add(hit);
|
try
|
||||||
|
|
||||||
if (cache.Count > MAX_CACHED_HITS)
|
|
||||||
{
|
{
|
||||||
await SaveHitCache(serverId);
|
await serverWaiter.WaitAsync();
|
||||||
|
var cache = _servers[serverId].HitCache;
|
||||||
|
cache.Add(hit);
|
||||||
|
|
||||||
|
if (cache.Count > MAX_CACHED_HITS)
|
||||||
|
{
|
||||||
|
await SaveHitCache(serverId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_log.WriteError("Could not store client kills");
|
||||||
|
_log.WriteDebug(e.GetExceptionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (serverWaiter.CurrentCount == 0)
|
||||||
|
{
|
||||||
|
serverWaiter.Release(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,9 +546,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if DEBUG
|
|
||||||
await Sync(attacker.CurrentServer);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -552,7 +557,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
waiter?.Release(1);
|
if (waiter?.CurrentCount == 0)
|
||||||
|
{
|
||||||
|
waiter.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,7 +569,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
using (var ctx = new DatabaseContext(true))
|
using (var ctx = new DatabaseContext(true))
|
||||||
{
|
{
|
||||||
var server = _servers[serverId];
|
var server = _servers[serverId];
|
||||||
ctx.AddRange(server.HitCache);
|
ctx.AddRange(server.HitCache.ToList());
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
server.HitCache.Clear();
|
server.HitCache.Clear();
|
||||||
}
|
}
|
||||||
@ -1110,21 +1118,41 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
long serverId = GetIdForServer(sv);
|
long serverId = GetIdForServer(sv);
|
||||||
|
|
||||||
using (var ctx = new DatabaseContext())
|
var waiter = _servers[serverId].OnSaving;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var serverStatsSet = ctx.Set<EFServerStatistics>();
|
await waiter.WaitAsync();
|
||||||
serverStatsSet.Update(_servers[serverId].ServerStatistics);
|
|
||||||
await ctx.SaveChangesAsync();
|
using (var ctx = new DatabaseContext())
|
||||||
|
{
|
||||||
|
var serverStatsSet = ctx.Set<EFServerStatistics>();
|
||||||
|
serverStatsSet.Update(_servers[serverId].ServerStatistics);
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var stats in sv.GetClientsAsList()
|
||||||
|
.Select(_client => _client.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY))
|
||||||
|
.Where(_stats => _stats != null))
|
||||||
|
{
|
||||||
|
await SaveClientStats(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
await SaveHitCache(serverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var stats in sv.GetClientsAsList()
|
catch (Exception e)
|
||||||
.Select(_client => _client.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY))
|
|
||||||
.Where(_stats => _stats != null))
|
|
||||||
{
|
{
|
||||||
await SaveClientStats(stats);
|
_log.WriteError("There was a probably syncing server stats");
|
||||||
|
_log.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
await SaveHitCache(serverId);
|
finally
|
||||||
|
{
|
||||||
|
if (waiter.CurrentCount == 0)
|
||||||
|
{
|
||||||
|
waiter.Release(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTeamBased(long serverId, bool isTeamBased)
|
public void SetTeamBased(long serverId, bool isTeamBased)
|
||||||
|
@ -43,7 +43,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Stop:
|
case GameEvent.EventType.Stop:
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Connect:
|
case GameEvent.EventType.PreConnect:
|
||||||
await Manager.AddPlayer(E.Origin);
|
await Manager.AddPlayer(E.Origin);
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Disconnect:
|
case GameEvent.EventType.Disconnect:
|
||||||
|
@ -73,7 +73,7 @@ namespace Tests
|
|||||||
};
|
};
|
||||||
|
|
||||||
_manager.GetEventHandler().AddEvent(e);
|
_manager.GetEventHandler().AddEvent(e);
|
||||||
e.OnProcessed.Wait();
|
e.Complete();
|
||||||
|
|
||||||
e = new GameEvent()
|
e = new GameEvent()
|
||||||
{
|
{
|
||||||
@ -92,7 +92,7 @@ namespace Tests
|
|||||||
};
|
};
|
||||||
|
|
||||||
_manager.GetEventHandler().AddEvent(e);
|
_manager.GetEventHandler().AddEvent(e);
|
||||||
e.OnProcessed.Wait();
|
e.Complete();
|
||||||
|
|
||||||
e = new GameEvent()
|
e = new GameEvent()
|
||||||
{
|
{
|
||||||
@ -111,7 +111,7 @@ namespace Tests
|
|||||||
};
|
};
|
||||||
|
|
||||||
_manager.GetEventHandler().AddEvent(e);
|
_manager.GetEventHandler().AddEvent(e);
|
||||||
e.OnProcessed.Wait();
|
e.Complete();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,13 +126,13 @@ namespace Tests
|
|||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
_manager.OnServerEvent += (sender, eventArgs) =>
|
//_manager.OnServerEvent += (sender, eventArgs) =>
|
||||||
{
|
//{
|
||||||
if (eventArgs.Event.Type == GameEvent.EventType.Connect)
|
// if (eventArgs.Event.Type == GameEvent.EventType.Connect)
|
||||||
{
|
// {
|
||||||
onJoined.Set();
|
// onJoined.Set();
|
||||||
}
|
// }
|
||||||
};
|
//};
|
||||||
|
|
||||||
server.EmulateClientJoinLog();
|
server.EmulateClientJoinLog();
|
||||||
onJoined.Wait();
|
onJoined.Wait();
|
||||||
@ -140,25 +140,25 @@ namespace Tests
|
|||||||
var client = server.Clients[0];
|
var client = server.Clients[0];
|
||||||
|
|
||||||
var warnEvent = client.Warn("test warn", Utilities.IW4MAdminClient(server));
|
var warnEvent = client.Warn("test warn", Utilities.IW4MAdminClient(server));
|
||||||
warnEvent.OnProcessed.Wait(5000);
|
warnEvent.WaitAsync(new TimeSpan(0, 0, 10), new CancellationToken()).Wait();
|
||||||
|
|
||||||
Assert.False(warnEvent.Failed);
|
Assert.False(warnEvent.Failed);
|
||||||
|
|
||||||
warnEvent = client.Warn("test warn", new EFClient() { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
warnEvent = client.Warn("test warn", new EFClient() { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
||||||
warnEvent.OnProcessed.Wait(5000);
|
warnEvent.WaitAsync(new TimeSpan(0, 0, 10), new CancellationToken()).Wait();
|
||||||
|
|
||||||
Assert.True(warnEvent.FailReason == GameEvent.EventFailReason.Permission &&
|
Assert.True(warnEvent.FailReason == GameEvent.EventFailReason.Permission &&
|
||||||
client.Warnings == 1, "warning was applied without proper permissions");
|
client.Warnings == 1, "warning was applied without proper permissions");
|
||||||
|
|
||||||
// warn clear
|
// warn clear
|
||||||
var warnClearEvent = client.WarnClear(new EFClient { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
var warnClearEvent = client.WarnClear(new EFClient { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
||||||
warnClearEvent.OnProcessed.Wait(5000);
|
warnClearEvent.WaitAsync(new TimeSpan(0, 0, 10), new CancellationToken()).Wait();
|
||||||
|
|
||||||
Assert.True(warnClearEvent.FailReason == GameEvent.EventFailReason.Permission &&
|
Assert.True(warnClearEvent.FailReason == GameEvent.EventFailReason.Permission &&
|
||||||
client.Warnings == 1, "warning was removed without proper permissions");
|
client.Warnings == 1, "warning was removed without proper permissions");
|
||||||
|
|
||||||
warnClearEvent = client.WarnClear(Utilities.IW4MAdminClient(server));
|
warnClearEvent = client.WarnClear(Utilities.IW4MAdminClient(server));
|
||||||
warnClearEvent.OnProcessed.Wait(5000);
|
warnClearEvent.WaitAsync(new TimeSpan(0, 0, 10), new CancellationToken()).Wait();
|
||||||
|
|
||||||
Assert.True(!warnClearEvent.Failed && client.Warnings == 0, "warning was not cleared");
|
Assert.True(!warnClearEvent.Failed && client.Warnings == 0, "warning was not cleared");
|
||||||
}
|
}
|
||||||
@ -178,14 +178,14 @@ namespace Tests
|
|||||||
var player = new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer };
|
var player = new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer };
|
||||||
player.SetAdditionalProperty("_reportCount", 3);
|
player.SetAdditionalProperty("_reportCount", 3);
|
||||||
var reportEvent = client.Report("test report", player);
|
var reportEvent = client.Report("test report", player);
|
||||||
reportEvent.OnProcessed.Wait(TestTimeout);
|
reportEvent.WaitAsync(new TimeSpan(0, 0, 10), new CancellationToken()).Wait();
|
||||||
|
|
||||||
Assert.True(reportEvent.FailReason == GameEvent.EventFailReason.Throttle &
|
Assert.True(reportEvent.FailReason == GameEvent.EventFailReason.Throttle &
|
||||||
client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 0, $"too many reports were applied [{reportEvent.FailReason.ToString()}]");
|
client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 0, $"too many reports were applied [{reportEvent.FailReason.ToString()}]");
|
||||||
|
|
||||||
// succeed
|
// succeed
|
||||||
reportEvent = client.Report("test report", new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
reportEvent = client.Report("test report", new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
||||||
reportEvent.OnProcessed.Wait(TestTimeout);
|
reportEvent.WaitAsync(new TimeSpan(0, 0, 10), new CancellationToken()).Wait();
|
||||||
|
|
||||||
Assert.True(!reportEvent.Failed &&
|
Assert.True(!reportEvent.Failed &&
|
||||||
client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 1, $"report was not applied [{reportEvent.FailReason.ToString()}]");
|
client.CurrentServer.Reports.Count(r => r.Target.NetworkId == client.NetworkId) == 1, $"report was not applied [{reportEvent.FailReason.ToString()}]");
|
||||||
@ -222,7 +222,7 @@ namespace Tests
|
|||||||
Assert.False(client == null, "no client found to flag");
|
Assert.False(client == null, "no client found to flag");
|
||||||
|
|
||||||
var flagEvent = client.Flag("test flag", new EFClient { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
var flagEvent = client.Flag("test flag", new EFClient { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
||||||
flagEvent.OnProcessed.Wait();
|
flagEvent.Complete();
|
||||||
|
|
||||||
// succeed
|
// succeed
|
||||||
Assert.True(!flagEvent.Failed &&
|
Assert.True(!flagEvent.Failed &&
|
||||||
@ -230,31 +230,31 @@ namespace Tests
|
|||||||
Assert.False(client.ReceivedPenalties.FirstOrDefault(p => p.Offense == "test flag") == null, "flag was not applied");
|
Assert.False(client.ReceivedPenalties.FirstOrDefault(p => p.Offense == "test flag") == null, "flag was not applied");
|
||||||
|
|
||||||
flagEvent = client.Flag("test flag", new EFClient { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
flagEvent = client.Flag("test flag", new EFClient { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
||||||
flagEvent.OnProcessed.Wait();
|
flagEvent.Complete();
|
||||||
|
|
||||||
// fail
|
// fail
|
||||||
Assert.True(client.ReceivedPenalties.Count == 1, "flag was applied without permisions");
|
Assert.True(client.ReceivedPenalties.Count == 1, "flag was applied without permisions");
|
||||||
|
|
||||||
flagEvent = client.Flag("test flag", new EFClient { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
flagEvent = client.Flag("test flag", new EFClient { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
||||||
flagEvent.OnProcessed.Wait();
|
flagEvent.Complete();
|
||||||
|
|
||||||
// fail
|
// fail
|
||||||
Assert.True(client.ReceivedPenalties.Count == 1, "duplicate flag was applied");
|
Assert.True(client.ReceivedPenalties.Count == 1, "duplicate flag was applied");
|
||||||
|
|
||||||
var unflagEvent = client.Unflag("test unflag", new EFClient { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
var unflagEvent = client.Unflag("test unflag", new EFClient { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
||||||
unflagEvent.OnProcessed.Wait();
|
unflagEvent.Complete();
|
||||||
|
|
||||||
// fail
|
// fail
|
||||||
Assert.False(client.Level == EFClient.Permission.User, "user was unflagged without permissions");
|
Assert.False(client.Level == EFClient.Permission.User, "user was unflagged without permissions");
|
||||||
|
|
||||||
unflagEvent = client.Unflag("test unflag", new EFClient { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
unflagEvent = client.Unflag("test unflag", new EFClient { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
||||||
unflagEvent.OnProcessed.Wait();
|
unflagEvent.Complete();
|
||||||
|
|
||||||
// succeed
|
// succeed
|
||||||
Assert.True(client.Level == EFClient.Permission.User, "user was not unflagged");
|
Assert.True(client.Level == EFClient.Permission.User, "user was not unflagged");
|
||||||
|
|
||||||
unflagEvent = client.Unflag("test unflag", new EFClient { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
unflagEvent = client.Unflag("test unflag", new EFClient { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
||||||
unflagEvent.OnProcessed.Wait();
|
unflagEvent.Complete();
|
||||||
|
|
||||||
// succeed
|
// succeed
|
||||||
Assert.True(unflagEvent.FailReason == GameEvent.EventFailReason.Invalid, "user was not flagged");
|
Assert.True(unflagEvent.FailReason == GameEvent.EventFailReason.Invalid, "user was not flagged");
|
||||||
@ -272,12 +272,12 @@ namespace Tests
|
|||||||
Assert.False(client == null, "no client found to kick");
|
Assert.False(client == null, "no client found to kick");
|
||||||
|
|
||||||
var kickEvent = client.Kick("test kick", new EFClient() { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
var kickEvent = client.Kick("test kick", new EFClient() { ClientId = 1, Level = EFClient.Permission.Banned, CurrentServer = client.CurrentServer });
|
||||||
kickEvent.OnProcessed.Wait();
|
kickEvent.Complete();
|
||||||
|
|
||||||
Assert.True(kickEvent.FailReason == GameEvent.EventFailReason.Permission, "client was kicked without permission");
|
Assert.True(kickEvent.FailReason == GameEvent.EventFailReason.Permission, "client was kicked without permission");
|
||||||
|
|
||||||
kickEvent = client.Kick("test kick", new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
kickEvent = client.Kick("test kick", new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer });
|
||||||
kickEvent.OnProcessed.Wait();
|
kickEvent.Complete();
|
||||||
|
|
||||||
Assert.True(_manager.Servers.First().GetClientsAsList().FirstOrDefault(c => c.NetworkId == client.NetworkId) == null, "client was not kicked");
|
Assert.True(_manager.Servers.First().GetClientsAsList().FirstOrDefault(c => c.NetworkId == client.NetworkId) == null, "client was not kicked");
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ namespace Tests
|
|||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
e.OnProcessed.Wait();
|
e.Complete();
|
||||||
|
|
||||||
var client = Manager.GetServers()[0].Clients[0];
|
var client = Manager.GetServers()[0].Clients[0];
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ namespace Tests
|
|||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
e.OnProcessed.Wait();
|
e.Complete();
|
||||||
|
|
||||||
Assert.True(client.Warnings == 1, "client wasn't warned for objectional language");
|
Assert.True(client.Warnings == 1, "client wasn't warned for objectional language");
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,11 @@ namespace Tests
|
|||||||
var currentClientCount = server.ClientNum;
|
var currentClientCount = server.ClientNum;
|
||||||
int eventsProcessed = 0;
|
int eventsProcessed = 0;
|
||||||
|
|
||||||
_manager.OnServerEvent += (sender, eventArgs) =>
|
/*_manager.OnServerEvent += (sender, eventArgs) =>
|
||||||
{
|
{
|
||||||
if (eventArgs.Event.Type == GameEvent.EventType.Connect)
|
if (eventArgs.Event.Type == GameEvent.EventType.Connect)
|
||||||
{
|
{
|
||||||
eventArgs.Event.OnProcessed.Wait();
|
eventArgs.Event.Complete();
|
||||||
Assert.False(eventArgs.Event.Failed, "connect event was not processed");
|
Assert.False(eventArgs.Event.Failed, "connect event was not processed");
|
||||||
Assert.True(server.ClientNum == currentClientCount + 1, "client count was not incremented");
|
Assert.True(server.ClientNum == currentClientCount + 1, "client count was not incremented");
|
||||||
eventsProcessed++;
|
eventsProcessed++;
|
||||||
@ -41,13 +41,13 @@ namespace Tests
|
|||||||
|
|
||||||
if (eventArgs.Event.Type == GameEvent.EventType.Disconnect)
|
if (eventArgs.Event.Type == GameEvent.EventType.Disconnect)
|
||||||
{
|
{
|
||||||
eventArgs.Event.OnProcessed.Wait();
|
eventArgs.Event.Complete();
|
||||||
Assert.False(eventArgs.Event.Failed, "disconnect event was not processed");
|
Assert.False(eventArgs.Event.Failed, "disconnect event was not processed");
|
||||||
Assert.True(server.ClientNum == currentClientCount, "client count was not decremented");
|
Assert.True(server.ClientNum == currentClientCount, "client count was not decremented");
|
||||||
eventsProcessed++;
|
eventsProcessed++;
|
||||||
resetEvent.Set();
|
resetEvent.Set();
|
||||||
}
|
}
|
||||||
};
|
};*/
|
||||||
|
|
||||||
server.EmulateClientJoinLog();
|
server.EmulateClientJoinLog();
|
||||||
|
|
||||||
@ -73,11 +73,11 @@ namespace Tests
|
|||||||
int eventsProcessed = 0;
|
int eventsProcessed = 0;
|
||||||
|
|
||||||
_manager.GetApplicationSettings().Configuration().RConPollRate = 5000;
|
_manager.GetApplicationSettings().Configuration().RConPollRate = 5000;
|
||||||
_manager.OnServerEvent += (sender, eventArgs) =>
|
/*_manager.OnServerEvent += (sender, eventArgs) =>
|
||||||
{
|
{
|
||||||
if (eventArgs.Event.Type == GameEvent.EventType.Connect)
|
if (eventArgs.Event.Type == GameEvent.EventType.Connect)
|
||||||
{
|
{
|
||||||
eventArgs.Event.OnProcessed.Wait();
|
eventArgs.Event.Complete();
|
||||||
Assert.False(eventArgs.Event.Failed, "connect event was not processed");
|
Assert.False(eventArgs.Event.Failed, "connect event was not processed");
|
||||||
Assert.True(server.ClientNum == currentClientCount + 1, "client count was not incremented");
|
Assert.True(server.ClientNum == currentClientCount + 1, "client count was not incremented");
|
||||||
eventsProcessed++;
|
eventsProcessed++;
|
||||||
@ -86,13 +86,13 @@ namespace Tests
|
|||||||
|
|
||||||
if (eventArgs.Event.Type == GameEvent.EventType.Disconnect)
|
if (eventArgs.Event.Type == GameEvent.EventType.Disconnect)
|
||||||
{
|
{
|
||||||
eventArgs.Event.OnProcessed.Wait();
|
eventArgs.Event.Complete();
|
||||||
Assert.False(eventArgs.Event.Failed, "disconnect event was not processed");
|
Assert.False(eventArgs.Event.Failed, "disconnect event was not processed");
|
||||||
Assert.True(server.ClientNum == currentClientCount, "client count was not decremented");
|
Assert.True(server.ClientNum == currentClientCount, "client count was not decremented");
|
||||||
eventsProcessed++;
|
eventsProcessed++;
|
||||||
resetEvent.Set();
|
resetEvent.Set();
|
||||||
}
|
}
|
||||||
};
|
};*/
|
||||||
|
|
||||||
(server.RconParser as TestRconParser).FakeClientCount = 1;
|
(server.RconParser as TestRconParser).FakeClientCount = 1;
|
||||||
|
|
||||||
|
@ -998,7 +998,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
var names = new List<string>(E.Target.AliasLink.Children.Select(a => a.Name));
|
var names = new List<string>(E.Target.AliasLink.Children.Select(a => a.Name));
|
||||||
var IPs = new List<string>(E.Target.AliasLink.Children.Select(a => a.IPAddress.ConvertIPtoString()).Distinct());
|
var IPs = new List<string>(E.Target.AliasLink.Children.Select(a => a.IPAddress.ConvertIPtoString()).Distinct());
|
||||||
|
|
||||||
E.Target.Tell($"[^3{E.Target}^7]");
|
E.Origin.Tell($"[^3{E.Target}^7]");
|
||||||
|
|
||||||
message.Append($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_ALIAS_ALIASES"]}: ");
|
message.Append($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_ALIAS_ALIASES"]}: ");
|
||||||
message.Append(String.Join(" | ", names));
|
message.Append(String.Join(" | ", names));
|
||||||
|
@ -22,40 +22,26 @@ namespace SharedLibraryCore.Database
|
|||||||
public DbSet<EFMeta> EFMeta { get; set; }
|
public DbSet<EFMeta> EFMeta { get; set; }
|
||||||
public DbSet<EFChangeHistory> EFChangeHistory { get; set; }
|
public DbSet<EFChangeHistory> EFChangeHistory { get; set; }
|
||||||
|
|
||||||
|
|
||||||
//[Obsolete]
|
|
||||||
//private static readonly ILoggerFactory _loggerFactory = new LoggerFactory(new[] {
|
|
||||||
// new ConsoleLoggerProvider((category, level) => level == LogLevel.Information, true)
|
|
||||||
//});
|
|
||||||
|
|
||||||
static string _ConnectionString;
|
static string _ConnectionString;
|
||||||
static string _provider;
|
static string _provider;
|
||||||
private static readonly string _migrationPluginDirectory = @"X:\IW4MAdmin\BUILD\Plugins";
|
private static readonly string _migrationPluginDirectory = @"X:\IW4MAdmin\BUILD\Plugins";
|
||||||
private static int activeContextCount;
|
private static readonly ILoggerFactory _loggerFactory = LoggerFactory.Create(builder =>
|
||||||
|
{
|
||||||
|
builder.AddConsole()
|
||||||
|
.AddDebug()
|
||||||
|
.AddFilter((category, level) => true);
|
||||||
|
});
|
||||||
|
|
||||||
public DatabaseContext(DbContextOptions<DatabaseContext> opt) : base(opt)
|
public DatabaseContext(DbContextOptions<DatabaseContext> opt) : base(opt)
|
||||||
{
|
{
|
||||||
#if DEBUG == true
|
|
||||||
activeContextCount++;
|
|
||||||
//Console.WriteLine($"Initialized DB Context #{activeContextCount}");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DatabaseContext()
|
public DatabaseContext()
|
||||||
{
|
{
|
||||||
#if DEBUG == true
|
|
||||||
activeContextCount++;
|
|
||||||
//Console.WriteLine($"Initialized DB Context #{activeContextCount}");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
#if DEBUG == true
|
|
||||||
|
|
||||||
//Console.WriteLine($"Disposed DB Context #{activeContextCount}");
|
|
||||||
activeContextCount--;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DatabaseContext(bool disableTracking) : this()
|
public DatabaseContext(bool disableTracking) : this()
|
||||||
@ -83,6 +69,9 @@ namespace SharedLibraryCore.Database
|
|||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
|
// optionsBuilder.UseLoggerFactory(_loggerFactory)
|
||||||
|
// .EnableSensitiveDataLogging();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_ConnectionString))
|
if (string.IsNullOrEmpty(_ConnectionString))
|
||||||
{
|
{
|
||||||
string currentPath = Utilities.OperatingDirectory;
|
string currentPath = Utilities.OperatingDirectory;
|
||||||
@ -153,6 +142,7 @@ namespace SharedLibraryCore.Database
|
|||||||
ent.HasIndex(a => a.Name);
|
ent.HasIndex(a => a.Name);
|
||||||
ent.Property(_alias => _alias.SearchableName).HasMaxLength(24);
|
ent.Property(_alias => _alias.SearchableName).HasMaxLength(24);
|
||||||
ent.HasIndex(_alias => _alias.SearchableName);
|
ent.HasIndex(_alias => _alias.SearchableName);
|
||||||
|
ent.HasIndex(_alias => new { _alias.Name, _alias.IPAddress }).IsUnique();
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<EFMeta>(ent =>
|
modelBuilder.Entity<EFMeta>(ent =>
|
||||||
|
@ -8,9 +8,6 @@ namespace SharedLibraryCore
|
|||||||
{
|
{
|
||||||
public class GameEvent
|
public class GameEvent
|
||||||
{
|
{
|
||||||
// define what the delagate function looks like
|
|
||||||
public delegate void OnServerEventEventHandler(object sender, GameEventArgs e);
|
|
||||||
|
|
||||||
public enum EventFailReason
|
public enum EventFailReason
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -205,11 +202,17 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
public GameEvent()
|
public GameEvent()
|
||||||
{
|
{
|
||||||
OnProcessed = new ManualResetEventSlim(false);
|
_eventFinishedWaiter = new ManualResetEvent(false);
|
||||||
Time = DateTime.UtcNow;
|
Time = DateTime.UtcNow;
|
||||||
Id = GetNextEventId();
|
Id = GetNextEventId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~GameEvent()
|
||||||
|
{
|
||||||
|
_eventFinishedWaiter.Set();
|
||||||
|
_eventFinishedWaiter.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
public EventType Type;
|
public EventType Type;
|
||||||
public EventRequiredEntity RequiredEntity { get; set; }
|
public EventRequiredEntity RequiredEntity { get; set; }
|
||||||
public string Data; // Data is usually the message sent by player
|
public string Data; // Data is usually the message sent by player
|
||||||
@ -219,34 +222,56 @@ namespace SharedLibraryCore
|
|||||||
public Server Owner;
|
public Server Owner;
|
||||||
public bool IsRemote { get; set; } = false;
|
public bool IsRemote { get; set; } = false;
|
||||||
public object Extra { get; set; }
|
public object Extra { get; set; }
|
||||||
public ManualResetEventSlim OnProcessed { get; set; }
|
private readonly ManualResetEvent _eventFinishedWaiter;
|
||||||
public DateTime Time { get; set; }
|
public DateTime Time { get; set; }
|
||||||
public long Id { get; private set; }
|
public long Id { get; private set; }
|
||||||
public EventFailReason FailReason { get; set; }
|
public EventFailReason FailReason { get; set; }
|
||||||
public bool Failed => FailReason != EventFailReason.None;
|
public bool Failed => FailReason != EventFailReason.None;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the event should block until it is complete
|
/// Indicates if the event should block until it is complete
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsBlocking { get; set; }
|
public bool IsBlocking { get; set; }
|
||||||
|
|
||||||
|
public void Complete()
|
||||||
|
{
|
||||||
|
_eventFinishedWaiter.Set();
|
||||||
|
#if DEBUG
|
||||||
|
Owner?.Logger.WriteDebug($"Completed internal for event {Id}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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(TimeSpan timeSpan, CancellationToken token)
|
public async Task<GameEvent> WaitAsync(TimeSpan timeSpan, CancellationToken token)
|
||||||
{
|
{
|
||||||
return Task.Run(() =>
|
bool processed = false;
|
||||||
{
|
|
||||||
bool processed = OnProcessed.Wait(timeSpan, token);
|
|
||||||
// this let's us know if the the action timed out
|
|
||||||
FailReason = FailReason == EventFailReason.None & !processed ? EventFailReason.Timeout : FailReason;
|
|
||||||
return this;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameEvent Wait()
|
#if DEBUG
|
||||||
{
|
Owner?.Logger.WriteDebug($"Begin wait for event {Id}");
|
||||||
OnProcessed.Wait();
|
#endif
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
processed = await Task.Run(() => _eventFinishedWaiter.WaitOne(timeSpan), token);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
|
||||||
|
if (!processed)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
//throw new Exception();
|
||||||
|
#endif
|
||||||
|
Owner?.Logger.WriteError("Waiting for event to complete timed out");
|
||||||
|
Owner?.Logger.WriteDebug($"{Id}, {Type}, {Data}, {Extra}, {FailReason.ToString()}, {Message}, {Origin}, {Target}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// this lets us know if the the action timed out
|
||||||
|
FailReason = FailReason == EventFailReason.None && !processed ? EventFailReason.Timeout : FailReason;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
string ExternalIPAddress { get; }
|
string ExternalIPAddress { get; }
|
||||||
CancellationToken CancellationToken { get; }
|
CancellationToken CancellationToken { get; }
|
||||||
bool IsRestartRequested { get; }
|
bool IsRestartRequested { get; }
|
||||||
OnServerEventEventHandler OnServerEvent { get; set; }
|
//OnServerEventEventHandler OnServerEvent { get; set; }
|
||||||
|
Task ExecuteEvent(GameEvent gameEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
909
SharedLibraryCore/Migrations/20191030000713_EnforceUniqueIndexForEFAliasIPName.Designer.cs
generated
Normal file
909
SharedLibraryCore/Migrations/20191030000713_EnforceUniqueIndexForEFAliasIPName.Designer.cs
generated
Normal file
@ -0,0 +1,909 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using SharedLibraryCore.Database;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20191030000713_EnforceUniqueIndexForEFAliasIPName")]
|
||||||
|
partial class EnforceUniqueIndexForEFAliasIPName
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.0.0");
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("SnapshotId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentSessionLength")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("CurrentStrain")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentViewAngleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Distance")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("HitDestinationId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("HitLocation")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("HitOriginId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("HitType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Hits")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Kills")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LastStrainAngleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("RecoilOffset")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<double>("SessionAngleOffset")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<double>("SessionAverageSnapValue")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<double>("SessionSPM")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("SessionScore")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SessionSnapHits")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("StrainAngleBetween")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("TimeSinceLastEvent")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("WeaponId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("SnapshotId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentViewAngleId");
|
||||||
|
|
||||||
|
b.HasIndex("HitDestinationId");
|
||||||
|
|
||||||
|
b.HasIndex("HitOriginId");
|
||||||
|
|
||||||
|
b.HasIndex("LastStrainAngleId");
|
||||||
|
|
||||||
|
b.ToTable("EFACSnapshot");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ACSnapshotVector3Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SnapshotId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Vector3Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ACSnapshotVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("SnapshotId");
|
||||||
|
|
||||||
|
b.HasIndex("Vector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFACSnapshotVector3");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("KillId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AttackerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Damage")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("DeathOriginVector3Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("DeathType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Fraction")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("HitLoc")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsKill")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("KillOriginVector3Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Map")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("VictimId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("ViewAnglesVector3Id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("VisibilityPercentage")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("Weapon")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("KillId");
|
||||||
|
|
||||||
|
b.HasIndex("AttackerId");
|
||||||
|
|
||||||
|
b.HasIndex("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("VictimId");
|
||||||
|
|
||||||
|
b.HasIndex("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFClientKills");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("MessageId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeSent")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("MessageId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("TimeSent");
|
||||||
|
|
||||||
|
b.ToTable("EFClientMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingHistoryId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientRatingHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("AverageRecoilOffset")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<double>("AverageSnapValue")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("Kills")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("MaxStrain")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<double>("RollingWeightedKDR")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<double>("SPM")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<double>("Skill")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("SnapHitCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TimePlayed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("VisionAverage")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("HitLocationCountId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("EFClientStatisticsClientId")
|
||||||
|
.HasColumnName("EFClientStatisticsClientId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("EFClientStatisticsServerId")
|
||||||
|
.HasColumnName("EFClientStatisticsServerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("HitCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float>("HitOffsetAverage")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("Location")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float>("MaxAngleDistance")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("HitLocationCountId");
|
||||||
|
|
||||||
|
b.HasIndex("EFClientStatisticsServerId");
|
||||||
|
|
||||||
|
b.HasIndex("EFClientStatisticsClientId", "EFClientStatisticsServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFHitLocationCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ActivityAmount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Newest")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Performance")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("Ranking")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("RatingHistoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long?>("ServerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("RatingId");
|
||||||
|
|
||||||
|
b.HasIndex("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("Performance", "Ranking", "When");
|
||||||
|
|
||||||
|
b.ToTable("EFRating");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("ServerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("EndPoint")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("GameName")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Port")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("StatisticId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("TotalKills")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("TotalPlayTime")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("StatisticId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServerStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateAdded")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("IPAddress")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(24);
|
||||||
|
|
||||||
|
b.Property<string>("SearchableName")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(24);
|
||||||
|
|
||||||
|
b.HasKey("AliasId");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("SearchableName");
|
||||||
|
|
||||||
|
b.HasIndex("Name", "IPAddress")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("EFAlias");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasLinkId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("AliasLinkId");
|
||||||
|
|
||||||
|
b.ToTable("EFAliasLinks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ChangeHistoryId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(128);
|
||||||
|
|
||||||
|
b.Property<string>("CurrentValue")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OriginEntityId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("PreviousValue")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TargetEntityId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeChanged")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TypeOfChange")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ChangeHistoryId");
|
||||||
|
|
||||||
|
b.ToTable("EFChangeHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AliasLinkId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Connections")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentAliasId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstConnection")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastConnection")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Level")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Masked")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("NetworkId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordSalt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TotalConnectionTime")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("AliasLinkId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentAliasId");
|
||||||
|
|
||||||
|
b.HasIndex("NetworkId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("EFClients");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MetaId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Extra")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasMaxLength(32);
|
||||||
|
|
||||||
|
b.Property<DateTime>("Updated")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("MetaId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("Key");
|
||||||
|
|
||||||
|
b.ToTable("EFMeta");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("PenaltyId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AutomatedOffense")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("Expires")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEvadedOffense")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("OffenderId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Offense")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PunisherId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("PenaltyId");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("OffenderId");
|
||||||
|
|
||||||
|
b.HasIndex("PunisherId");
|
||||||
|
|
||||||
|
b.ToTable("EFPenalties");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Vector3Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float>("X")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Y")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Z")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Vector3Id");
|
||||||
|
|
||||||
|
b.ToTable("Vector3");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentViewAngleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitDestinationId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitOriginId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LastStrainAngleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", "Snapshot")
|
||||||
|
.WithMany("PredictedViewAngles")
|
||||||
|
.HasForeignKey("SnapshotId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "Vector")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Vector3Id")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AttackerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("VictimId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ViewAnglesVector3Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("EFClientStatisticsClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("EFClientStatisticsServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", null)
|
||||||
|
.WithMany("HitLocations")
|
||||||
|
.HasForeignKey("EFClientStatisticsClientId", "EFClientStatisticsServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
|
||||||
|
.WithMany("Ratings")
|
||||||
|
.HasForeignKey("RatingHistoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("Children")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AliasLinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentAliasId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany("Meta")
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("OffenderId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
|
||||||
|
.WithMany("AdministeredPenalties")
|
||||||
|
.HasForeignKey("PunisherId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
public partial class EnforceUniqueIndexForEFAliasIPName : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (migrationBuilder.ActiveProvider == "Pomelo.EntityFrameworkCore.MySql")
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql(@"CREATE TEMPORARY TABLE DUPLICATE_ALIASES
|
||||||
|
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`;
|
||||||
|
SET
|
||||||
|
SQL_SAFE_UPDATES = 0;
|
||||||
|
UPDATE
|
||||||
|
`EFClients` AS `Client`
|
||||||
|
JOIN
|
||||||
|
DUPLICATE_ALIASES `Duplicate`
|
||||||
|
ON
|
||||||
|
`Client`.CurrentAliasId = `Duplicate`.`MIN`
|
||||||
|
SET
|
||||||
|
`Client`.CurrentAliasId = `Duplicate`.`MAX`
|
||||||
|
WHERE
|
||||||
|
`Client`.`CurrentAliasId` IN(
|
||||||
|
SELECT
|
||||||
|
`MIN`
|
||||||
|
FROM
|
||||||
|
DUPLICATE_ALIASES
|
||||||
|
);
|
||||||
|
DELETE
|
||||||
|
FROM
|
||||||
|
`EFAlias`
|
||||||
|
WHERE
|
||||||
|
`AliasId` IN(
|
||||||
|
SELECT
|
||||||
|
`MIN`
|
||||||
|
FROM
|
||||||
|
DUPLICATE_ALIASES
|
||||||
|
);
|
||||||
|
SET
|
||||||
|
SQL_SAFE_UPDATES = 1;
|
||||||
|
DROP TABLE
|
||||||
|
DUPLICATE_ALIASES;");
|
||||||
|
}
|
||||||
|
|
||||||
|
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.CreateIndex(
|
||||||
|
name: "IX_EFAlias_Name_IPAddress",
|
||||||
|
table: "EFAlias",
|
||||||
|
columns: new[] { "Name", "IPAddress" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_EFAlias_Name_IPAddress",
|
||||||
|
table: "EFAlias");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -464,14 +464,13 @@ namespace SharedLibraryCore.Migrations
|
|||||||
|
|
||||||
b.HasKey("AliasId");
|
b.HasKey("AliasId");
|
||||||
|
|
||||||
b.HasIndex("IPAddress");
|
|
||||||
|
|
||||||
b.HasIndex("LinkId");
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
b.HasIndex("Name");
|
|
||||||
|
|
||||||
b.HasIndex("SearchableName");
|
b.HasIndex("SearchableName");
|
||||||
|
|
||||||
|
b.HasIndex("Name", "IPAddress")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("EFAlias");
|
b.ToTable("EFAlias");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Database.Models
|
namespace SharedLibraryCore.Database.Models
|
||||||
@ -82,6 +82,12 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
{ "_reportCount", 0 }
|
{ "_reportCount", 0 }
|
||||||
};
|
};
|
||||||
ReceivedPenalties = new List<EFPenalty>();
|
ReceivedPenalties = new List<EFPenalty>();
|
||||||
|
ProcessingEvent = new SemaphoreSlim(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
~EFClient()
|
||||||
|
{
|
||||||
|
ProcessingEvent.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
@ -108,6 +114,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string IPAddressString => IPAddress.ConvertIPtoString();
|
public string IPAddressString => IPAddress.ConvertIPtoString();
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public virtual IDictionary<int, long> LinkedAccounts { get; set; }
|
public virtual IDictionary<int, long> LinkedAccounts { get; set; }
|
||||||
|
|
||||||
@ -452,13 +459,10 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles any client related logic on connection
|
/// Handles any client related logic on connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool OnConnect()
|
public bool IsAbleToConnectSimple()
|
||||||
{
|
{
|
||||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
|
|
||||||
LastConnection = DateTime.UtcNow;
|
|
||||||
Connections += 1;
|
|
||||||
|
|
||||||
string strippedName = Name.StripColors();
|
string strippedName = Name.StripColors();
|
||||||
if (string.IsNullOrWhiteSpace(Name) || strippedName.Replace(" ", "").Length < 3)
|
if (string.IsNullOrWhiteSpace(Name) || strippedName.Replace(" ", "").Length < 3)
|
||||||
{
|
{
|
||||||
@ -524,27 +528,29 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
{
|
{
|
||||||
IPAddress = ipAddress;
|
IPAddress = ipAddress;
|
||||||
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
||||||
|
CurrentServer.Logger.WriteDebug($"Updated alias for {this}");
|
||||||
await CurrentServer.Manager.GetClientService().Update(this);
|
await CurrentServer.Manager.GetClientService().Update(this);
|
||||||
|
CurrentServer.Logger.WriteDebug($"Updated client for {this}");
|
||||||
|
|
||||||
bool canConnect = await CanConnect(ipAddress);
|
bool canConnect = await CanConnect(ipAddress);
|
||||||
|
|
||||||
if (canConnect)
|
if (!canConnect)
|
||||||
|
{
|
||||||
|
CurrentServer.Logger.WriteDebug($"Client {this} is not allowed to join the server");
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Join,
|
Type = GameEvent.EventType.Join,
|
||||||
Origin = this,
|
Origin = this,
|
||||||
Target = this,
|
Target = this,
|
||||||
Owner = CurrentServer
|
Owner = CurrentServer,
|
||||||
};
|
};
|
||||||
|
|
||||||
CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CurrentServer.Logger.WriteDebug($"Client {this} is not allowed to join the server");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -560,6 +566,13 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
var autoKickClient = Utilities.IW4MAdminClient(CurrentServer);
|
var autoKickClient = Utilities.IW4MAdminClient(CurrentServer);
|
||||||
|
|
||||||
|
bool isAbleToConnectSimple = IsAbleToConnectSimple();
|
||||||
|
|
||||||
|
if (!isAbleToConnectSimple)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// we want to get any penalties that are tied to their IP or AliasLink (but not necessarily their GUID)
|
// we want to get any penalties that are tied to their IP or AliasLink (but not necessarily their GUID)
|
||||||
var activePenalties = await CurrentServer.Manager.GetPenaltyService().GetActivePenaltiesAsync(AliasLinkId, ipAddress);
|
var activePenalties = await CurrentServer.Manager.GetPenaltyService().GetActivePenaltiesAsync(AliasLinkId, ipAddress);
|
||||||
|
|
||||||
@ -609,7 +622,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
Unflag(Utilities.CurrentLocalization.LocalizationIndex["SERVER_AUTOFLAG_UNFLAG"], autoKickClient);
|
Unflag(Utilities.CurrentLocalization.LocalizationIndex["SERVER_AUTOFLAG_UNFLAG"], autoKickClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OnConnect();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
@ -661,6 +674,29 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
.LocalizationIndex[$"GLOBAL_PERMISSION_{Level.ToString().ToUpper()}"]
|
.LocalizationIndex[$"GLOBAL_PERMISSION_{Level.ToString().ToUpper()}"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public SemaphoreSlim ProcessingEvent;
|
||||||
|
|
||||||
|
public async Task Lock()
|
||||||
|
{
|
||||||
|
bool result = await ProcessingEvent.WaitAsync(Utilities.DefaultCommandTimeout);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unlock()
|
||||||
|
{
|
||||||
|
if (ProcessingEvent.CurrentCount == 0)
|
||||||
|
{
|
||||||
|
ProcessingEvent.Release(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return ((EFClient)obj).NetworkId == this.NetworkId;
|
return ((EFClient)obj).NetworkId == this.NetworkId;
|
||||||
|
@ -19,19 +19,25 @@ namespace SharedLibraryCore
|
|||||||
private Jint.Engine ScriptEngine;
|
private Jint.Engine ScriptEngine;
|
||||||
private readonly string FileName;
|
private readonly string FileName;
|
||||||
private IManager Manager;
|
private IManager Manager;
|
||||||
|
private readonly FileSystemWatcher _watcher;
|
||||||
|
|
||||||
public ScriptPlugin(string fileName)
|
public ScriptPlugin(string fileName)
|
||||||
{
|
{
|
||||||
FileName = fileName;
|
FileName = fileName;
|
||||||
var watcher = new FileSystemWatcher()
|
_watcher = new FileSystemWatcher()
|
||||||
{
|
{
|
||||||
Path = $"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}",
|
Path = $"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}",
|
||||||
NotifyFilter = NotifyFilters.Size,
|
NotifyFilter = NotifyFilters.Size,
|
||||||
Filter = fileName.Split(Path.DirectorySeparatorChar).Last()
|
Filter = fileName.Split(Path.DirectorySeparatorChar).Last()
|
||||||
};
|
};
|
||||||
|
|
||||||
watcher.Changed += Watcher_Changed;
|
_watcher.Changed += Watcher_Changed;
|
||||||
watcher.EnableRaisingEvents = true;
|
_watcher.EnableRaisingEvents = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScriptPlugin()
|
||||||
|
{
|
||||||
|
_watcher.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Watcher_Changed(object sender, FileSystemEventArgs e)
|
private async void Watcher_Changed(object sender, FileSystemEventArgs e)
|
||||||
|
@ -67,7 +67,7 @@ namespace SharedLibraryCore
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="P">EFClient pulled from memory reading</param>
|
/// <param name="P">EFClient pulled from memory reading</param>
|
||||||
/// <returns>True if player added sucessfully, false otherwise</returns>
|
/// <returns>True if player added sucessfully, false otherwise</returns>
|
||||||
public abstract Task OnClientConnected(EFClient P);
|
public abstract Task<EFClient> OnClientConnected(EFClient P);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove player by client number
|
/// Remove player by client number
|
||||||
|
@ -21,19 +21,23 @@ namespace SharedLibraryCore.Services
|
|||||||
|
|
||||||
if (entity.IPAddress != null)
|
if (entity.IPAddress != null)
|
||||||
{
|
{
|
||||||
var existingAlias = await context.Aliases
|
var existingAliases = await context.Aliases
|
||||||
.Select(_alias => new { _alias.AliasId, _alias.LinkId, _alias.IPAddress, _alias.Name })
|
.Select(_alias => new { _alias.AliasId, _alias.LinkId, _alias.IPAddress, _alias.Name })
|
||||||
.FirstOrDefaultAsync(_alias => _alias.IPAddress == entity.IPAddress);
|
.Where(_alias => _alias.IPAddress == entity.IPAddress)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
if (existingAlias != null)
|
if (existingAliases.Count > 0)
|
||||||
{
|
{
|
||||||
entity.CurrentServer.Logger.WriteDebug($"[create] client with new GUID {entity} has existing link {existingAlias.LinkId}");
|
linkId = existingAliases.First().LinkId;
|
||||||
|
|
||||||
linkId = existingAlias.LinkId;
|
entity.CurrentServer.Logger.WriteDebug($"[create] client with new GUID {entity} has existing link {linkId}");
|
||||||
if (existingAlias.Name == entity.Name)
|
|
||||||
|
var existingExactAlias = existingAliases.FirstOrDefault(_alias => _alias.Name == entity.Name);
|
||||||
|
|
||||||
|
if (existingExactAlias != null)
|
||||||
{
|
{
|
||||||
entity.CurrentServer.Logger.WriteDebug($"[create] client with new GUID {entity} has existing alias {existingAlias.AliasId}");
|
entity.CurrentServer.Logger.WriteDebug($"[create] client with new GUID {entity} has existing alias {existingExactAlias.AliasId}");
|
||||||
aliasId = existingAlias.AliasId;
|
aliasId = existingExactAlias.AliasId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,6 +103,8 @@ namespace SharedLibraryCore.Services
|
|||||||
|
|
||||||
private async Task UpdateAlias(string name, int? ip, EFClient entity, DatabaseContext context)
|
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
|
// entity is the tracked db context item
|
||||||
// get all aliases by IP address and LinkId
|
// get all aliases by IP address and LinkId
|
||||||
var iqAliases = context.Aliases
|
var iqAliases = context.Aliases
|
||||||
@ -106,11 +112,33 @@ namespace SharedLibraryCore.Services
|
|||||||
// we only want alias that have the same IP address or share a link
|
// we only want alias that have the same IP address or share a link
|
||||||
.Where(_alias => _alias.IPAddress == ip || (_alias.LinkId == entity.AliasLinkId));
|
.Where(_alias => _alias.IPAddress == ip || (_alias.LinkId == entity.AliasLinkId));
|
||||||
|
|
||||||
#if DEBUG == true
|
|
||||||
var aliasSql = iqAliases.ToSql();
|
|
||||||
#endif
|
|
||||||
var aliases = await iqAliases.ToListAsync();
|
var aliases = await iqAliases.ToListAsync();
|
||||||
|
|
||||||
|
//// update each of the aliases where this is no IP but the name is identical
|
||||||
|
//foreach (var alias in aliases.Where(_alias => (_alias.IPAddress == null || _alias.IPAddress == 0)))
|
||||||
|
//{
|
||||||
|
// alias.IPAddress = ip;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//// remove any possible duplicates after updating
|
||||||
|
//foreach (var aliasGroup in aliases.GroupBy(_alias => new { _alias.IPAddress, _alias.Name })
|
||||||
|
// .Where(_group => _group.Count() > 1))
|
||||||
|
//{
|
||||||
|
// var oldestDuplicateAlias = aliasGroup.OrderBy(_alias => _alias.DateAdded).First();
|
||||||
|
|
||||||
|
// entity.CurrentServer.Manager.GetLogger(0).WriteDebug($"Oldest duplicate is {oldestDuplicateAlias.AliasId}");
|
||||||
|
|
||||||
|
// await context.Clients.Where(_client => aliasGroup.Select(_grp => _grp.AliasId).Contains(_client.CurrentAliasId))
|
||||||
|
// .ForEachAsync(_client => _client.CurrentAliasId = oldestDuplicateAlias.AliasId);
|
||||||
|
|
||||||
|
// var duplicateAliases = aliasGroup.Where(_alias => _alias.AliasId != oldestDuplicateAlias.AliasId);
|
||||||
|
// context.RemoveRange(duplicateAliases);
|
||||||
|
|
||||||
|
// await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
// entity.CurrentServer.Manager.GetLogger(0).WriteDebug($"Removed duplicate aliases {string.Join(",", duplicateAliases.Select(_alias => _alias.AliasId))}");
|
||||||
|
//}
|
||||||
|
|
||||||
// see if they have a matching IP + Name but new NetworkId
|
// see if they have a matching IP + Name but new NetworkId
|
||||||
var existingExactAlias = aliases.FirstOrDefault(a => a.Name == name && a.IPAddress == ip);
|
var existingExactAlias = aliases.FirstOrDefault(a => a.Name == name && a.IPAddress == ip);
|
||||||
bool hasExactAliasMatch = existingExactAlias != null;
|
bool hasExactAliasMatch = existingExactAlias != null;
|
||||||
@ -125,12 +153,6 @@ namespace SharedLibraryCore.Services
|
|||||||
bool hasExistingAlias = aliases.Count > 0;
|
bool hasExistingAlias = aliases.Count > 0;
|
||||||
bool isAliasLinkUpdated = newAliasLink.AliasLinkId != entity.AliasLink.AliasLinkId;
|
bool isAliasLinkUpdated = newAliasLink.AliasLinkId != entity.AliasLink.AliasLinkId;
|
||||||
|
|
||||||
// update each of the aliases where this is no IP but the name is identical
|
|
||||||
foreach (var alias in aliases.Where(_alias => (_alias.IPAddress == null || _alias.IPAddress == 0)))
|
|
||||||
{
|
|
||||||
alias.IPAddress = ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
// this happens when the link we found is different than the one we create before adding an IP
|
// this happens when the link we found is different than the one we create before adding an IP
|
||||||
@ -191,9 +213,12 @@ namespace SharedLibraryCore.Services
|
|||||||
|
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
entity.CurrentServer.Logger.WriteDebug($"[updatealias] {entity} has exact alias match, so we're going to try to remove aliasId {oldAlias.AliasId} with linkId {oldAlias.AliasId}");
|
if (context.Entry(oldAlias).State != EntityState.Deleted)
|
||||||
context.Aliases.Remove(oldAlias);
|
{
|
||||||
await context.SaveChangesAsync();
|
entity.CurrentServer.Logger.WriteDebug($"[updatealias] {entity} has exact alias match, so we're going to try to remove aliasId {oldAlias.AliasId} with linkId {oldAlias.AliasId}");
|
||||||
|
context.Aliases.Remove(oldAlias);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,6 +241,8 @@ namespace SharedLibraryCore.Services
|
|||||||
entity.CurrentAliasId = 0;
|
entity.CurrentAliasId = 0;
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entity.CurrentServer.Manager.GetLogger(0).WriteDebug($"End update alias for {entity}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -286,18 +313,41 @@ namespace SharedLibraryCore.Services
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<EFClient> Get(int entityID)
|
public async Task<EFClient> Get(int entityId)
|
||||||
{
|
{
|
||||||
|
// todo: this needs to be optimized for large linked accounts
|
||||||
using (var context = new DatabaseContext(true))
|
using (var context = new DatabaseContext(true))
|
||||||
{
|
{
|
||||||
var iqClient = from _c in context.Clients
|
|
||||||
.Include(c => c.CurrentAlias)
|
|
||||||
.Include(c => c.AliasLink.Children)
|
|
||||||
.Include(c => c.Meta)
|
|
||||||
where _c.ClientId == entityID
|
|
||||||
select _c;
|
|
||||||
|
|
||||||
var client = await iqClient.FirstOrDefaultAsync();
|
var client = context.Clients
|
||||||
|
.Select(_client => new EFClient()
|
||||||
|
{
|
||||||
|
ClientId = _client.ClientId,
|
||||||
|
AliasLinkId = _client.AliasLinkId,
|
||||||
|
Level = _client.Level,
|
||||||
|
Connections = _client.Connections,
|
||||||
|
FirstConnection = _client.FirstConnection,
|
||||||
|
LastConnection = _client.LastConnection,
|
||||||
|
Masked = _client.Masked,
|
||||||
|
NetworkId = _client.NetworkId,
|
||||||
|
CurrentAlias = new EFAlias()
|
||||||
|
{
|
||||||
|
Name = _client.CurrentAlias.Name,
|
||||||
|
IPAddress = _client.CurrentAlias.IPAddress
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.FirstOrDefault(_client => _client.ClientId == entityId);
|
||||||
|
|
||||||
|
client.AliasLink = new EFAliasLink()
|
||||||
|
{
|
||||||
|
Children = await context.Aliases
|
||||||
|
.Where(_alias => _alias.LinkId == client.AliasLinkId)
|
||||||
|
.Select(_alias => new EFAlias()
|
||||||
|
{
|
||||||
|
Name = _alias.Name,
|
||||||
|
IPAddress = _alias.IPAddress
|
||||||
|
}).ToListAsync()
|
||||||
|
};
|
||||||
|
|
||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
@ -337,8 +387,19 @@ namespace SharedLibraryCore.Services
|
|||||||
EF.CompileAsyncQuery((DatabaseContext context, long networkId) =>
|
EF.CompileAsyncQuery((DatabaseContext context, long networkId) =>
|
||||||
context.Clients
|
context.Clients
|
||||||
.Include(c => c.CurrentAlias)
|
.Include(c => c.CurrentAlias)
|
||||||
.Include(c => c.AliasLink.Children)
|
//.Include(c => c.AliasLink.Children)
|
||||||
.Include(c => c.ReceivedPenalties)
|
//.Include(c => c.ReceivedPenalties)
|
||||||
|
.Select(_client => new EFClient()
|
||||||
|
{
|
||||||
|
ClientId = _client.ClientId,
|
||||||
|
AliasLinkId = _client.AliasLinkId,
|
||||||
|
Level = _client.Level,
|
||||||
|
Connections = _client.Connections,
|
||||||
|
FirstConnection = _client.FirstConnection,
|
||||||
|
LastConnection = _client.LastConnection,
|
||||||
|
Masked = _client.Masked,
|
||||||
|
NetworkId = _client.NetworkId
|
||||||
|
})
|
||||||
.FirstOrDefault(c => c.NetworkId == networkId)
|
.FirstOrDefault(c => c.NetworkId == networkId)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -74,6 +74,13 @@ namespace SharedLibraryCore.Services
|
|||||||
return await ctx.EFMeta
|
return await ctx.EFMeta
|
||||||
.Where(_meta => _meta.Key == metaKey)
|
.Where(_meta => _meta.Key == metaKey)
|
||||||
.Where(_meta => _meta.ClientId == client.ClientId)
|
.Where(_meta => _meta.ClientId == client.ClientId)
|
||||||
|
.Select(_meta => new EFMeta()
|
||||||
|
{
|
||||||
|
MetaId = _meta.MetaId,
|
||||||
|
Key = _meta.Key,
|
||||||
|
ClientId = _meta.ClientId,
|
||||||
|
Value = _meta.Value
|
||||||
|
})
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||||
<PackageReference Include="Npgsql" Version="4.1.1" />
|
<PackageReference Include="Npgsql" Version="4.1.1" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.0.1" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.0.1" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.0.0-rc1.final" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.0.0-rc3.final" />
|
||||||
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace SharedLibraryCore
|
|||||||
#endif
|
#endif
|
||||||
public static Encoding EncodingType;
|
public static Encoding EncodingType;
|
||||||
public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary<string, string>());
|
public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary<string, string>());
|
||||||
public static TimeSpan DefaultCommandTimeout = new TimeSpan(0, 0, 10);
|
public static TimeSpan DefaultCommandTimeout = new TimeSpan(0, 0, 25);
|
||||||
|
|
||||||
public static EFClient IW4MAdminClient(Server server = null)
|
public static EFClient IW4MAdminClient(Server server = null)
|
||||||
{
|
{
|
||||||
|
@ -45,17 +45,17 @@ namespace WebfrontCore.Controllers
|
|||||||
NetworkId = client.NetworkId,
|
NetworkId = client.NetworkId,
|
||||||
Meta = new List<ProfileMeta>(),
|
Meta = new List<ProfileMeta>(),
|
||||||
Aliases = client.AliasLink.Children
|
Aliases = client.AliasLink.Children
|
||||||
.Where(a => a.Name != client.Name)
|
|
||||||
.Select(a => a.Name)
|
.Select(a => a.Name)
|
||||||
.Distinct()
|
.Prepend(client.Name)
|
||||||
.OrderBy(a => a)
|
.OrderBy(a => a)
|
||||||
|
.Distinct()
|
||||||
.ToList(),
|
.ToList(),
|
||||||
IPs = client.AliasLink.Children
|
IPs = client.AliasLink.Children
|
||||||
|
.Where(i => i.IPAddress != null)
|
||||||
|
.OrderByDescending(i => i.DateAdded)
|
||||||
.Select(i => i.IPAddress.ConvertIPtoString())
|
.Select(i => i.IPAddress.ConvertIPtoString())
|
||||||
.Union(new List<string>() { client.CurrentAlias.IPAddress.ConvertIPtoString() })
|
.Prepend(client.CurrentAlias.IPAddress.ConvertIPtoString())
|
||||||
.Where(i => !string.IsNullOrEmpty(i))
|
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.OrderBy(i => i)
|
|
||||||
.ToList(),
|
.ToList(),
|
||||||
HasActivePenalty = activePenalties.Count() > 0,
|
HasActivePenalty = activePenalties.Count() > 0,
|
||||||
ActivePenaltyType = activePenalties.Count() > 0 ? activePenalties.First().Type.ToString() : null,
|
ActivePenaltyType = activePenalties.Count() > 0 ? activePenalties.First().Type.ToString() : null,
|
||||||
@ -139,7 +139,7 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
var clientsDto = await Manager.GetClientService().FindClientsByIdentifier(clientName);
|
var clientsDto = await Manager.GetClientService().FindClientsByIdentifier(clientName);
|
||||||
|
|
||||||
foreach(var client in clientsDto)
|
foreach (var client in clientsDto)
|
||||||
{
|
{
|
||||||
if (!Authorized && ((Permission)client.LevelInt).ShouldHideLevel())
|
if (!Authorized && ((Permission)client.LevelInt).ShouldHideLevel())
|
||||||
{
|
{
|
||||||
@ -152,7 +152,7 @@ namespace WebfrontCore.Controllers
|
|||||||
return View("Find/Index", clientsDto);
|
return View("Find/Index", clientsDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> Meta(int id, int count, int offset, DateTime? startAt)
|
public async Task<IActionResult> GetMeta(int id, int count, int offset, DateTime? startAt)
|
||||||
{
|
{
|
||||||
IEnumerable<ProfileMeta> meta = await MetaService.GetRuntimeMeta(id, startAt == null ? offset : 0, count, startAt ?? DateTime.UtcNow);
|
IEnumerable<ProfileMeta> meta = await MetaService.GetRuntimeMeta(id, startAt == null ? offset : 0, count, startAt ?? DateTime.UtcNow);
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ namespace WebfrontCore.Middleware
|
|||||||
public ClaimsPermissionRemoval(RequestDelegate nextRequest, IManager manager)
|
public ClaimsPermissionRemoval(RequestDelegate nextRequest, IManager manager)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_manager.OnServerEvent += OnGameEvent;
|
//_manager.OnServerEvent += OnGameEvent;
|
||||||
_privilegedClientIds = new List<int>();
|
_privilegedClientIds = new List<int>();
|
||||||
_nextRequest = nextRequest;
|
_nextRequest = nextRequest;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user