fixes for new polling setup
update database model for alias (nullable ip) heartbeats now send ip to master server
This commit is contained in:
parent
9bdd7d1b8a
commit
5ac8a55c72
@ -9,6 +9,8 @@ namespace IW4MAdmin.Application.API.Master
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; set; }
|
||||
[JsonProperty("ip")]
|
||||
public string IPAddress { get; set; }
|
||||
[JsonProperty("port")]
|
||||
public short Port { get; set; }
|
||||
[JsonProperty("gametype")]
|
||||
|
@ -44,7 +44,8 @@ namespace IW4MAdmin.Application.API.Master
|
||||
Map = s.CurrentMap.Name,
|
||||
MaxClientNum = s.MaxClients,
|
||||
Id = s.GetHashCode(),
|
||||
Port = (short)s.GetPort()
|
||||
Port = (short)s.GetPort(),
|
||||
IPAddress = s.IP
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Objects;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace IW4MAdmin.Application.EventParsers
|
||||
{
|
||||
@ -149,7 +147,11 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
Owner = server,
|
||||
Origin = new EFClient()
|
||||
{
|
||||
Name = regexMatch.Groups[4].ToString().StripColors(),
|
||||
CurrentAlias = new EFAlias()
|
||||
{
|
||||
Active = false,
|
||||
Name = regexMatch.Groups[4].ToString().StripColors(),
|
||||
},
|
||||
NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
|
||||
ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()),
|
||||
State = EFClient.ClientState.Connecting,
|
||||
@ -171,7 +173,11 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
Owner = server,
|
||||
Origin = new EFClient()
|
||||
{
|
||||
Name = regexMatch.Groups[4].ToString().StripColors(),
|
||||
CurrentAlias = new EFAlias()
|
||||
{
|
||||
Active = false,
|
||||
Name = regexMatch.Groups[4].ToString().StripColors()
|
||||
},
|
||||
NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
|
||||
ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()),
|
||||
State = EFClient.ClientState.Disconnecting
|
||||
@ -217,6 +223,9 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
}
|
||||
|
||||
// other parsers can derive from this parser so we make it virtual
|
||||
public virtual string GetGameDir() => "userraw";
|
||||
public virtual string GetGameDir()
|
||||
{
|
||||
return "userraw";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,16 @@
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace IW4MAdmin.Application.EventParsers
|
||||
{
|
||||
class IW5EventParser : IW4EventParser
|
||||
{
|
||||
public override string GetGameDir() => "logs";
|
||||
public override string GetGameDir()
|
||||
{
|
||||
return "logs";
|
||||
}
|
||||
|
||||
public override GameEvent GetEvent(Server server, string logLine)
|
||||
{
|
||||
@ -28,7 +26,11 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
{
|
||||
NetworkId = lineSplit[1].ConvertLong(),
|
||||
ClientNumber = clientNum,
|
||||
Name = lineSplit[3]
|
||||
CurrentAlias = new EFAlias()
|
||||
{
|
||||
Active = false,
|
||||
Name = lineSplit[3]
|
||||
}
|
||||
};
|
||||
|
||||
return new GameEvent()
|
||||
@ -48,7 +50,9 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return base.GetEvent(server, logLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,12 +28,12 @@ namespace IW4MAdmin.Application.IO
|
||||
|
||||
public long Length => -1;
|
||||
|
||||
public int UpdateInterval => 1000;
|
||||
public int UpdateInterval => 350;
|
||||
|
||||
public async Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
||||
{
|
||||
#if DEBUG == true
|
||||
server.Logger.WriteDebug($"Begin reading {fileSizeDiff} from http log");
|
||||
server.Logger.WriteDebug($"Begin reading from http log");
|
||||
#endif
|
||||
var events = new List<GameEvent>();
|
||||
string b64Path = server.LogPath.ToBase64UrlSafeString();
|
||||
|
@ -75,27 +75,9 @@ namespace IW4MAdmin
|
||||
// client has connected in the past
|
||||
else
|
||||
{
|
||||
var existingAlias = client.AliasLink.Children
|
||||
.FirstOrDefault(a => a.Name == clientFromLog.Name);
|
||||
|
||||
if (existingAlias == null)
|
||||
{
|
||||
Logger.WriteDebug($"Client {clientFromLog} has connected previously under a different ip/name");
|
||||
client.CurrentAlias = new EFAlias()
|
||||
{
|
||||
// this gets updated on client join
|
||||
IPAddress = clientFromLog.IPAddress,
|
||||
Name = clientFromLog.Name,
|
||||
};
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
client.CurrentAlias = existingAlias;
|
||||
client.CurrentAliasId = existingAlias.AliasId;
|
||||
}
|
||||
|
||||
await Manager.GetClientService().Update(client);
|
||||
// this is only a temporary version until the IPAddress is transmitted
|
||||
client.CurrentAlias.Active = false;
|
||||
client.CurrentAlias.Name = clientFromLog.Name;
|
||||
}
|
||||
|
||||
Logger.WriteInfo($"Client {client} connected...");
|
||||
@ -108,14 +90,15 @@ namespace IW4MAdmin
|
||||
client.CurrentServer = this;
|
||||
|
||||
Clients[client.ClientNumber] = client;
|
||||
client.OnConnect();
|
||||
|
||||
// this only happens the preconnect event occurred from RCon polling
|
||||
if (clientFromLog.IPAddress != 0)
|
||||
// this only happens if the preconnect event occurred from RCon polling
|
||||
if (clientFromLog.IPAddress.HasValue)
|
||||
{
|
||||
await client.OnJoin(clientFromLog.IPAddress);
|
||||
}
|
||||
|
||||
client.OnConnect();
|
||||
|
||||
client.State = EFClient.ClientState.Connected;
|
||||
#if DEBUG == true
|
||||
Logger.WriteDebug($"End PreConnect for {client}");
|
||||
@ -218,11 +201,23 @@ namespace IW4MAdmin
|
||||
/// <returns></returns>
|
||||
override protected async Task<bool> ProcessEvent(GameEvent E)
|
||||
{
|
||||
if (E.Type == GameEvent.EventType.PreConnect)
|
||||
if (E.Type == GameEvent.EventType.ChangePermission)
|
||||
{
|
||||
bool clientExists = GetClientsAsList().Exists(_client => _client.NetworkId.Equals(E.Origin));
|
||||
if (!E.Target.IsPrivileged())
|
||||
{
|
||||
// remove banned or demoted privileged user
|
||||
Manager.GetPrivilegedClients().Remove(E.Target.ClientId);
|
||||
}
|
||||
|
||||
if (!clientExists)
|
||||
else
|
||||
{
|
||||
Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
|
||||
}
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.PreConnect)
|
||||
{
|
||||
if (Clients[E.Origin.ClientNumber] == null)
|
||||
{
|
||||
#if DEBUG == true
|
||||
Logger.WriteDebug($"Begin PreConnect for {E.Origin}");
|
||||
@ -468,7 +463,8 @@ namespace IW4MAdmin
|
||||
client.Ping = origin.Ping;
|
||||
client.Score = origin.Score;
|
||||
|
||||
if (origin.IPAddress == 0)
|
||||
// update their IP if it hasn't been set yet
|
||||
if (!client.IPAddress.HasValue)
|
||||
{
|
||||
return client.OnJoin(origin.IPAddress);
|
||||
}
|
||||
@ -499,17 +495,9 @@ namespace IW4MAdmin
|
||||
#endif
|
||||
Throttled = false;
|
||||
|
||||
foreach (var client in polledClients)
|
||||
{
|
||||
// todo: move out somehwere
|
||||
var existingClient = Clients[client.ClientNumber] ?? client;
|
||||
existingClient.Ping = client.Ping;
|
||||
existingClient.Score = client.Score;
|
||||
}
|
||||
|
||||
var disconnectingClients = currentClients.Except(polledClients);
|
||||
var connectingClients = polledClients.Except(currentClients);
|
||||
var updatedClients = polledClients.Except(connectingClients);
|
||||
var updatedClients = polledClients.Except(connectingClients).Except(disconnectingClients);
|
||||
|
||||
return new List<EFClient>[]
|
||||
{
|
||||
@ -753,6 +741,7 @@ namespace IW4MAdmin
|
||||
infoResponse["fs_game"];
|
||||
var logfile = await this.GetDvarAsync<string>("g_log");
|
||||
var logsync = await this.GetDvarAsync<int>("g_logsync");
|
||||
var ip = await this.GetDvarAsync<string>("net_ip");
|
||||
|
||||
WorkingDirectory = basepath.Value;
|
||||
|
||||
@ -774,6 +763,8 @@ namespace IW4MAdmin
|
||||
this.MaxClients = maxplayers;
|
||||
this.FSGame = game;
|
||||
this.Gametype = gametype;
|
||||
this.IP = ip.Value;
|
||||
|
||||
if (logsync.Value == 0 || logfile.Value == string.Empty)
|
||||
{
|
||||
// this DVAR isn't set until the a map is loaded
|
||||
@ -1000,8 +991,6 @@ namespace IW4MAdmin
|
||||
};
|
||||
|
||||
await Manager.GetPenaltyService().Create(newPenalty);
|
||||
// prevent them from logging in again
|
||||
Manager.GetPrivilegedClients().Remove(Target.ClientId);
|
||||
}
|
||||
|
||||
override public async Task Unban(string reason, EFClient Target, EFClient Origin)
|
||||
|
@ -1,25 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
|
||||
using IW4MAdmin.Application.API.Master;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Commands;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Objects;
|
||||
using SharedLibraryCore.Services;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Database;
|
||||
using SharedLibraryCore.Events;
|
||||
|
||||
using IW4MAdmin.Application.API.Master;
|
||||
using IW4MAdmin.Application.Migration;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Events;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IW4MAdmin.Application
|
||||
{
|
||||
@ -61,7 +57,6 @@ namespace IW4MAdmin.Application
|
||||
ClientSvc = new ClientService();
|
||||
AliasSvc = new AliasService();
|
||||
PenaltySvc = new PenaltyService();
|
||||
PrivilegedClients = new Dictionary<int, EFClient>();
|
||||
ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
|
||||
StartTime = DateTime.UtcNow;
|
||||
OnQuit = new ManualResetEventSlim();
|
||||
@ -85,61 +80,12 @@ namespace IW4MAdmin.Application
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
{
|
||||
await newEvent.Owner.ExecuteEvent(newEvent);
|
||||
|
||||
await newEvent.Owner.ExecuteEvent(newEvent);
|
||||
|
||||
// save the event info to the database
|
||||
var changeHistorySvc = new ChangeHistoryService();
|
||||
await changeHistorySvc.Add(args.Event);
|
||||
|
||||
// todo: this is a hacky mess
|
||||
if (newEvent.Origin?.DelayedEvents.Count > 0 &&
|
||||
(//newEvent.Origin?.State == Player.ClientState.Connected ||
|
||||
newEvent.Type == GameEvent.EventType.Connect))
|
||||
{
|
||||
var events = newEvent.Origin.DelayedEvents;
|
||||
|
||||
// add the delayed event to the queue
|
||||
while (events.Count > 0)
|
||||
{
|
||||
var oldEvent = events.Dequeue();
|
||||
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = oldEvent.Type,
|
||||
Origin = newEvent.Origin,
|
||||
Data = oldEvent.Data,
|
||||
Extra = oldEvent.Extra,
|
||||
Owner = oldEvent.Owner,
|
||||
Message = oldEvent.Message,
|
||||
Target = oldEvent.Target,
|
||||
Remote = oldEvent.Remote
|
||||
};
|
||||
|
||||
e.Origin = newEvent.Origin;
|
||||
// check if the target was assigned
|
||||
if (e.Target != null)
|
||||
{
|
||||
// update the target incase they left or have newer info
|
||||
e.Target = newEvent.Owner.GetClientsAsList()
|
||||
.FirstOrDefault(p => p.NetworkId == e.Target.NetworkId);
|
||||
// we have to throw out the event because they left
|
||||
if (e.Target == null)
|
||||
{
|
||||
Logger.WriteWarning($"Delayed event for {e.Origin} was ignored because the target has left");
|
||||
// hack: don't do anything with the event because the target is invalid
|
||||
e.Origin = null;
|
||||
e.Type = GameEvent.EventType.Unknown;
|
||||
|
||||
}
|
||||
}
|
||||
Logger.WriteDebug($"Adding delayed event of type {e.Type} for {e.Origin} back for processing");
|
||||
this.GetEventHandler().AddEvent(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// save the event info to the database
|
||||
var changeHistorySvc = new ChangeHistoryService();
|
||||
await changeHistorySvc.Add(args.Event);
|
||||
|
||||
#if DEBUG
|
||||
Logger.WriteDebug($"Processed event with id {newEvent.Id}");
|
||||
@ -173,7 +119,7 @@ namespace IW4MAdmin.Application
|
||||
Logger.WriteDebug(ex.GetExceptionInfo());
|
||||
}
|
||||
|
||||
skip:
|
||||
skip:
|
||||
|
||||
// tell anyone waiting for the output that we're done
|
||||
newEvent.OnProcessed.Set();
|
||||
@ -263,36 +209,7 @@ namespace IW4MAdmin.Application
|
||||
await new ContextSeed(db).Seed();
|
||||
}
|
||||
|
||||
// todo: optimize this (or replace it)
|
||||
var ipList = (await ClientSvc.Find(c => c.Level > EFClient.Permission.Trusted))
|
||||
.Select(c => new
|
||||
{
|
||||
c.Password,
|
||||
c.PasswordSalt,
|
||||
c.ClientId,
|
||||
c.Level,
|
||||
c.Name
|
||||
});
|
||||
|
||||
foreach (var a in ipList)
|
||||
{
|
||||
try
|
||||
{
|
||||
PrivilegedClients.Add(a.ClientId, new EFClient()
|
||||
{
|
||||
Name = a.Name,
|
||||
ClientId = a.ClientId,
|
||||
Level = a.Level,
|
||||
PasswordSalt = a.PasswordSalt,
|
||||
Password = a.Password
|
||||
});
|
||||
}
|
||||
|
||||
catch (ArgumentException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PrivilegedClients = (await ClientSvc.GetPrivilegedClients()).ToDictionary(_client => _client.ClientId);
|
||||
#endregion
|
||||
|
||||
#region CONFIG
|
||||
@ -341,7 +258,9 @@ namespace IW4MAdmin.Application
|
||||
}
|
||||
|
||||
else if (config.Servers.Count == 0)
|
||||
{
|
||||
throw new ServerException("A server configuration in IW4MAdminSettings.json is invalid");
|
||||
}
|
||||
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Utilities.EncodingType = Encoding.GetEncoding(!string.IsNullOrEmpty(config.CustomParserEncoding) ? config.CustomParserEncoding : "windows-1252");
|
||||
@ -367,7 +286,9 @@ namespace IW4MAdmin.Application
|
||||
|
||||
#region COMMANDS
|
||||
if (ClientSvc.GetOwners().Result.Count == 0)
|
||||
{
|
||||
Commands.Add(new COwner());
|
||||
}
|
||||
|
||||
Commands.Add(new CQuit());
|
||||
Commands.Add(new CKick());
|
||||
@ -408,7 +329,9 @@ namespace IW4MAdmin.Application
|
||||
Commands.Add(new CNextMap());
|
||||
|
||||
foreach (Command C in SharedLibraryCore.Plugins.PluginImporter.ActiveCommands)
|
||||
{
|
||||
Commands.Add(C);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region INIT
|
||||
@ -443,7 +366,9 @@ namespace IW4MAdmin.Application
|
||||
{
|
||||
Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_UNFIXABLE"]} [{Conf.IPAddress}:{Conf.Port}]");
|
||||
if (e.GetType() == typeof(DvarException))
|
||||
{
|
||||
Logger.WriteDebug($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_DVAR"]} {(e as DvarException).Data["dvar_name"]} ({Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_DVAR_HELP"]})");
|
||||
}
|
||||
else if (e.GetType() == typeof(NetworkException))
|
||||
{
|
||||
Logger.WriteDebug(e.Message);
|
||||
@ -572,23 +497,59 @@ namespace IW4MAdmin.Application
|
||||
return MessageTokens;
|
||||
}
|
||||
|
||||
public IList<EFClient> GetActiveClients() => _servers.SelectMany(s => s.Clients).Where(p => p != null).ToList();
|
||||
public IList<EFClient> GetActiveClients()
|
||||
{
|
||||
return _servers.SelectMany(s => s.Clients).Where(p => p != null).ToList();
|
||||
}
|
||||
|
||||
public ClientService GetClientService() => ClientSvc;
|
||||
public AliasService GetAliasService() => AliasSvc;
|
||||
public PenaltyService GetPenaltyService() => PenaltySvc;
|
||||
public IConfigurationHandler<ApplicationConfiguration> GetApplicationSettings() => ConfigHandler;
|
||||
public IDictionary<int, EFClient> GetPrivilegedClients() => PrivilegedClients;
|
||||
public bool ShutdownRequested() => !Running;
|
||||
public IEventHandler GetEventHandler() => Handler;
|
||||
public ClientService GetClientService()
|
||||
{
|
||||
return ClientSvc;
|
||||
}
|
||||
|
||||
public AliasService GetAliasService()
|
||||
{
|
||||
return AliasSvc;
|
||||
}
|
||||
|
||||
public PenaltyService GetPenaltyService()
|
||||
{
|
||||
return PenaltySvc;
|
||||
}
|
||||
|
||||
public IConfigurationHandler<ApplicationConfiguration> GetApplicationSettings()
|
||||
{
|
||||
return ConfigHandler;
|
||||
}
|
||||
|
||||
public IDictionary<int, EFClient> GetPrivilegedClients()
|
||||
{
|
||||
return PrivilegedClients;
|
||||
}
|
||||
|
||||
public bool ShutdownRequested()
|
||||
{
|
||||
return !Running;
|
||||
}
|
||||
|
||||
public IEventHandler GetEventHandler()
|
||||
{
|
||||
return Handler;
|
||||
}
|
||||
|
||||
public void SetHasEvent()
|
||||
{
|
||||
OnQuit.Set();
|
||||
}
|
||||
|
||||
public IList<Assembly> GetPluginAssemblies() => SharedLibraryCore.Plugins.PluginImporter.PluginAssemblies;
|
||||
public IList<Assembly> GetPluginAssemblies()
|
||||
{
|
||||
return SharedLibraryCore.Plugins.PluginImporter.PluginAssemblies;
|
||||
}
|
||||
|
||||
public IPageList GetPageList() => PageList;
|
||||
public IPageList GetPageList()
|
||||
{
|
||||
return PageList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.RCon;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Objects;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.RCon;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
|
||||
namespace IW4MAdmin.Application.RconParsers
|
||||
{
|
||||
@ -73,14 +71,19 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
return (await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, $"set {dvarName} {dvarValue}")).Length > 0;
|
||||
}
|
||||
|
||||
public virtual CommandPrefix GetCommandPrefixes() => Prefixes;
|
||||
public virtual CommandPrefix GetCommandPrefixes()
|
||||
{
|
||||
return Prefixes;
|
||||
}
|
||||
|
||||
private List<EFClient> ClientsFromStatus(string[] Status)
|
||||
{
|
||||
List<EFClient> StatusPlayers = new List<EFClient>();
|
||||
|
||||
if (Status.Length < 4)
|
||||
{
|
||||
throw new ServerException("Unexpected status response received");
|
||||
}
|
||||
|
||||
int validMatches = 0;
|
||||
foreach (String S in Status)
|
||||
@ -103,13 +106,21 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
ping = int.Parse(regex.Groups[3].Value);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
long networkId = regex.Groups[4].Value.ConvertLong();
|
||||
string name = regex.Groups[5].Value.StripColors().Trim();
|
||||
int ip = regex.Groups[7].Value.Split(':')[0].ConvertToIP();
|
||||
|
||||
var P = new EFClient()
|
||||
{
|
||||
Name = name,
|
||||
CurrentAlias = new EFAlias()
|
||||
{
|
||||
Name = name
|
||||
},
|
||||
NetworkId = networkId,
|
||||
ClientNumber = clientNumber,
|
||||
IPAddress = ip == 0 ? int.MinValue : ip,
|
||||
|
@ -23,7 +23,8 @@ class Instance(Resource):
|
||||
def put(self, id):
|
||||
try:
|
||||
for server in request.json['servers']:
|
||||
server['ip'] = request.remote_addr
|
||||
if 'ip' not in server or server['ip'] == 'localhost':
|
||||
server['ip'] = request.remote_addr
|
||||
instance = InstanceSchema().load(request.json)
|
||||
except ValidationError as err:
|
||||
return {'message' : err.messages }, 400
|
||||
@ -34,7 +35,8 @@ class Instance(Resource):
|
||||
def post(self):
|
||||
try:
|
||||
for server in request.json['servers']:
|
||||
server['ip'] = request.remote_addr
|
||||
if 'ip' not in server or server['ip'] == 'localhost':
|
||||
server['ip'] = request.remote_addr
|
||||
instance = InstanceSchema().load(request.json)
|
||||
except ValidationError as err:
|
||||
return {'message' : err.messages }, 400
|
||||
|
@ -25,7 +25,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
private ILogger Log;
|
||||
private readonly IManager Manager;
|
||||
|
||||
|
||||
private readonly SemaphoreSlim OnProcessingPenalty;
|
||||
private readonly SemaphoreSlim OnProcessingSensitive;
|
||||
|
||||
@ -348,7 +347,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
Log.WriteWarning("Could not add client to detection");
|
||||
}
|
||||
|
||||
Log.WriteInfo($"Adding {pl} to stats");
|
||||
pl.CurrentServer.Logger.WriteInfo($"Adding {pl} to stats");
|
||||
}
|
||||
|
||||
return clientStats;
|
||||
|
@ -250,7 +250,7 @@ namespace Tests
|
||||
unbanCommand.ExecuteAsync(new GameEvent()
|
||||
{
|
||||
Origin = new EFClient() { ClientId = 1, Level = EFClient.Permission.Console, CurrentServer = client.CurrentServer },
|
||||
Target = Manager.GetClientService().Find(c => c.NetworkId == client.NetworkId).Result.First().AsEFClient(),
|
||||
Target = Manager.GetClientService().Find(c => c.NetworkId == client.NetworkId).Result.First(),
|
||||
Data = "test unban",
|
||||
Type = GameEvent.EventType.Command,
|
||||
Owner = client.CurrentServer
|
||||
|
@ -84,7 +84,7 @@ namespace IW4MAdmin.Plugins.Welcome
|
||||
|
||||
public async Task OnEventAsync(GameEvent E, Server S)
|
||||
{
|
||||
if (E.Type == GameEvent.EventType.Connect)
|
||||
if (E.Type == GameEvent.EventType.Join)
|
||||
{
|
||||
EFClient newPlayer = E.Origin;
|
||||
if (newPlayer.Level >= Permission.Trusted && !E.Origin.Masked)
|
||||
|
@ -37,11 +37,25 @@ namespace SharedLibraryCore.Commands
|
||||
{
|
||||
if ((await (E.Owner.Manager.GetClientService() as ClientService).GetOwners()).Count == 0)
|
||||
{
|
||||
var oldPermission = E.Origin.Level;
|
||||
E.Origin.Level = EFClient.Permission.Owner;
|
||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_OWNER_SUCCESS"]);
|
||||
// so setpassword/login works
|
||||
E.Owner.Manager.GetPrivilegedClients().Add(E.Origin.ClientId, E.Origin);
|
||||
await E.Owner.Manager.GetClientService().Update(E.Origin);
|
||||
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.ChangePermission,
|
||||
Origin = E.Origin,
|
||||
Target = E.Origin,
|
||||
Owner = E.Owner,
|
||||
Extra = new Change()
|
||||
{
|
||||
PreviousValue = oldPermission.ToString(),
|
||||
NewValue = E.Origin.Level.ToString()
|
||||
}
|
||||
};
|
||||
|
||||
E.Owner.Manager.GetEventHandler().AddEvent(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -494,17 +508,6 @@ namespace SharedLibraryCore.Commands
|
||||
await E.Owner.Manager.GetClientService().Update(E.Target);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
E.Owner.Manager.GetPrivilegedClients().Add(E.Target.ClientId, E.Target);
|
||||
}
|
||||
|
||||
catch (Exception)
|
||||
{
|
||||
// this updates their privilege level to the webfront claims
|
||||
E.Owner.Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
|
||||
}
|
||||
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Origin = E.Origin,
|
||||
|
@ -22,7 +22,7 @@ namespace SharedLibraryCore.Database
|
||||
|
||||
static string _ConnectionString;
|
||||
static string _provider;
|
||||
private static string _migrationPluginDirectory = @"X:\IW4MAdmin\BUILD\Plugins\";
|
||||
private static readonly string _migrationPluginDirectory = @"X:\IW4MAdmin\BUILD\Plugins\";
|
||||
|
||||
public DatabaseContext(DbContextOptions<DatabaseContext> opt) : base(opt) { }
|
||||
|
||||
@ -110,6 +110,7 @@ namespace SharedLibraryCore.Database
|
||||
|
||||
modelBuilder.Entity<EFAlias>(ent =>
|
||||
{
|
||||
ent.Property(a => a.IPAddress).IsRequired(false);
|
||||
ent.HasIndex(a => a.IPAddress);
|
||||
ent.Property(a => a.Name).HasMaxLength(24);
|
||||
ent.HasIndex(a => a.Name);
|
||||
@ -123,14 +124,15 @@ namespace SharedLibraryCore.Database
|
||||
|
||||
// adapted from
|
||||
// https://aleemkhan.wordpress.com/2013/02/28/dynamically-adding-dbset-properties-in-dbcontext-for-entity-framework-code-first/
|
||||
#if DEBUG
|
||||
string pluginDir = _migrationPluginDirectory;
|
||||
#else
|
||||
string pluginDir = Path.Join(Utilities.OperatingDirectory, "Plugins");
|
||||
#endif
|
||||
IEnumerable<string> directoryFiles = Directory.GetFiles(pluginDir).Where(f => f.EndsWith(".dll"));
|
||||
|
||||
#if DEBUG == TRUE
|
||||
foreach (string dllPath in Directory.GetFiles(_migrationPluginDirectory).Where(f => f.EndsWith(".dll")))
|
||||
#else
|
||||
|
||||
foreach (string dllPath in directoryFiles)
|
||||
#endif
|
||||
{
|
||||
Assembly library;
|
||||
try
|
||||
|
@ -16,7 +16,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
[MaxLength(24)]
|
||||
public string Name { get; set; }
|
||||
[Required]
|
||||
public int IPAddress { get; set; }
|
||||
public int? IPAddress { get; set; }
|
||||
[Required]
|
||||
public DateTime DateAdded { get; set; }
|
||||
}
|
||||
|
@ -44,14 +44,14 @@ namespace SharedLibraryCore.Database.Models
|
||||
set { CurrentAlias.Name = value; }
|
||||
}
|
||||
[NotMapped]
|
||||
public virtual int IPAddress
|
||||
public virtual int? IPAddress
|
||||
{
|
||||
get { return CurrentAlias.IPAddress; }
|
||||
set { CurrentAlias.IPAddress = value; }
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
public string IPAddressString => new System.Net.IPAddress(BitConverter.GetBytes(IPAddress)).ToString();
|
||||
public string IPAddressString => IPAddress.ConvertIPtoString();
|
||||
[NotMapped]
|
||||
public virtual IDictionary<int, long> LinkedAccounts { get; set; }
|
||||
|
||||
|
@ -208,38 +208,5 @@ namespace SharedLibraryCore
|
||||
return this;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// determine whether an event should be delayed or not
|
||||
/// applies only to the origin entity
|
||||
/// </summary>
|
||||
/// <param name="queuedEvent">event to determine status for</param>
|
||||
/// <returns>true if event should be delayed, false otherwise</returns>
|
||||
public static bool ShouldOriginEventBeDelayed(GameEvent queuedEvent)
|
||||
{
|
||||
return queuedEvent.Origin != null &&
|
||||
(queuedEvent.Origin.State != EFClient.ClientState.Connected &&
|
||||
// we want to allow join and quit events
|
||||
queuedEvent.Type != EventType.Connect &&
|
||||
queuedEvent.Type != EventType.Join &&
|
||||
queuedEvent.Type != EventType.Quit &&
|
||||
queuedEvent.Type != EventType.Disconnect &&
|
||||
// we don't care about unknown events
|
||||
queuedEvent.Origin.NetworkId != 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// determine whether an event should be delayed or not
|
||||
/// applies only to the target entity
|
||||
/// </summary>
|
||||
/// <param name="queuedEvent">event to determine status for</param>
|
||||
/// <returns>true if event should be delayed, false otherwise</returns>
|
||||
public static bool ShouldTargetEventBeDelayed(GameEvent queuedEvent)
|
||||
{
|
||||
return (queuedEvent.Target != null && queuedEvent.Target.ClientNumber != -1) &&
|
||||
(queuedEvent.Target.State != EFClient.ClientState.Connected &&
|
||||
queuedEvent.Target.NetworkId != 0 &&
|
||||
queuedEvent.Origin?.ClientId != 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
690
SharedLibraryCore/Migrations/20181125193243_MakeClientIPNullable.Designer.cs
generated
Normal file
690
SharedLibraryCore/Migrations/20181125193243_MakeClientIPNullable.Designer.cs
generated
Normal file
@ -0,0 +1,690 @@
|
||||
// <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("20181125193243_MakeClientIPNullable")]
|
||||
partial class MakeClientIPNullable
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.4-rtm-31024");
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||
{
|
||||
b.Property<int>("SnapshotId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("ClientId");
|
||||
|
||||
b.Property<int>("CurrentSessionLength");
|
||||
|
||||
b.Property<double>("CurrentStrain");
|
||||
|
||||
b.Property<int>("CurrentViewAngleId");
|
||||
|
||||
b.Property<int>("Deaths");
|
||||
|
||||
b.Property<double>("Distance");
|
||||
|
||||
b.Property<double>("EloRating");
|
||||
|
||||
b.Property<int>("HitDestinationId");
|
||||
|
||||
b.Property<int>("HitLocation");
|
||||
|
||||
b.Property<int>("HitOriginId");
|
||||
|
||||
b.Property<int>("HitType");
|
||||
|
||||
b.Property<int>("Hits");
|
||||
|
||||
b.Property<int>("Kills");
|
||||
|
||||
b.Property<int>("LastStrainAngleId");
|
||||
|
||||
b.Property<double>("SessionAngleOffset");
|
||||
|
||||
b.Property<double>("SessionSPM");
|
||||
|
||||
b.Property<int>("SessionScore");
|
||||
|
||||
b.Property<double>("StrainAngleBetween");
|
||||
|
||||
b.Property<int>("TimeSinceLastEvent");
|
||||
|
||||
b.Property<int>("WeaponId");
|
||||
|
||||
b.Property<DateTime>("When");
|
||||
|
||||
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.EFClientKill", b =>
|
||||
{
|
||||
b.Property<long>("KillId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("AttackerId");
|
||||
|
||||
b.Property<int>("Damage");
|
||||
|
||||
b.Property<int?>("DeathOriginVector3Id");
|
||||
|
||||
b.Property<int>("DeathType");
|
||||
|
||||
b.Property<double>("Fraction");
|
||||
|
||||
b.Property<int>("HitLoc");
|
||||
|
||||
b.Property<bool>("IsKill");
|
||||
|
||||
b.Property<int?>("KillOriginVector3Id");
|
||||
|
||||
b.Property<int>("Map");
|
||||
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<int>("VictimId");
|
||||
|
||||
b.Property<int?>("ViewAnglesVector3Id");
|
||||
|
||||
b.Property<double>("VisibilityPercentage");
|
||||
|
||||
b.Property<int>("Weapon");
|
||||
|
||||
b.Property<DateTime>("When");
|
||||
|
||||
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();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("ClientId");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<DateTime>("TimeSent");
|
||||
|
||||
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();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("ClientId");
|
||||
|
||||
b.HasKey("RatingHistoryId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.ToTable("EFClientRatingHistory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||
{
|
||||
b.Property<int>("ClientId");
|
||||
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("Deaths");
|
||||
|
||||
b.Property<double>("EloRating");
|
||||
|
||||
b.Property<int>("Kills");
|
||||
|
||||
b.Property<double>("MaxStrain");
|
||||
|
||||
b.Property<double>("RollingWeightedKDR");
|
||||
|
||||
b.Property<double>("SPM");
|
||||
|
||||
b.Property<double>("Skill");
|
||||
|
||||
b.Property<int>("TimePlayed");
|
||||
|
||||
b.Property<double>("VisionAverage");
|
||||
|
||||
b.HasKey("ClientId", "ServerId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("EFClientStatistics");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||
{
|
||||
b.Property<int>("HitLocationCountId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("ClientId")
|
||||
.HasColumnName("EFClientStatistics_ClientId");
|
||||
|
||||
b.Property<int>("HitCount");
|
||||
|
||||
b.Property<float>("HitOffsetAverage");
|
||||
|
||||
b.Property<int>("Location");
|
||||
|
||||
b.Property<float>("MaxAngleDistance");
|
||||
|
||||
b.Property<int>("ServerId")
|
||||
.HasColumnName("EFClientStatistics_ServerId");
|
||||
|
||||
b.HasKey("HitLocationCountId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.HasIndex("ClientId", "ServerId");
|
||||
|
||||
b.ToTable("EFHitLocationCounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||
{
|
||||
b.Property<int>("RatingId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("ActivityAmount");
|
||||
|
||||
b.Property<bool>("Newest");
|
||||
|
||||
b.Property<double>("Performance");
|
||||
|
||||
b.Property<int>("Ranking");
|
||||
|
||||
b.Property<int>("RatingHistoryId");
|
||||
|
||||
b.Property<int?>("ServerId");
|
||||
|
||||
b.Property<DateTime>("When");
|
||||
|
||||
b.HasKey("RatingId");
|
||||
|
||||
b.HasIndex("Performance");
|
||||
|
||||
b.HasIndex("Ranking");
|
||||
|
||||
b.HasIndex("RatingHistoryId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.HasIndex("When");
|
||||
|
||||
b.ToTable("EFRating");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||
{
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("Port");
|
||||
|
||||
b.HasKey("ServerId");
|
||||
|
||||
b.ToTable("EFServers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||
{
|
||||
b.Property<int>("StatisticId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<long>("TotalKills");
|
||||
|
||||
b.Property<long>("TotalPlayTime");
|
||||
|
||||
b.HasKey("StatisticId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("EFServerStatistics");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||
{
|
||||
b.Property<int>("AliasId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<DateTime>("DateAdded");
|
||||
|
||||
b.Property<int?>("IPAddress");
|
||||
|
||||
b.Property<int>("LinkId");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(24);
|
||||
|
||||
b.HasKey("AliasId");
|
||||
|
||||
b.HasIndex("IPAddress");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
b.HasIndex("Name");
|
||||
|
||||
b.ToTable("EFAlias");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
|
||||
{
|
||||
b.Property<int>("AliasLinkId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.HasKey("AliasLinkId");
|
||||
|
||||
b.ToTable("EFAliasLinks");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
|
||||
{
|
||||
b.Property<int>("ChangeHistoryId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<string>("Comment")
|
||||
.HasMaxLength(128);
|
||||
|
||||
b.Property<string>("CurrentValue");
|
||||
|
||||
b.Property<int>("OriginEntityId");
|
||||
|
||||
b.Property<string>("PreviousValue");
|
||||
|
||||
b.Property<int>("TargetEntityId");
|
||||
|
||||
b.Property<DateTime>("TimeChanged");
|
||||
|
||||
b.Property<int>("TypeOfChange");
|
||||
|
||||
b.HasKey("ChangeHistoryId");
|
||||
|
||||
b.ToTable("EFChangeHistory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||
{
|
||||
b.Property<int>("ClientId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("AliasLinkId");
|
||||
|
||||
b.Property<int>("Connections");
|
||||
|
||||
b.Property<int>("CurrentAliasId");
|
||||
|
||||
b.Property<DateTime>("FirstConnection");
|
||||
|
||||
b.Property<DateTime>("LastConnection");
|
||||
|
||||
b.Property<int>("Level");
|
||||
|
||||
b.Property<bool>("Masked");
|
||||
|
||||
b.Property<long>("NetworkId");
|
||||
|
||||
b.Property<string>("Password");
|
||||
|
||||
b.Property<string>("PasswordSalt");
|
||||
|
||||
b.Property<int>("TotalConnectionTime");
|
||||
|
||||
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();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("ClientId");
|
||||
|
||||
b.Property<DateTime>("Created");
|
||||
|
||||
b.Property<string>("Extra");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<DateTime>("Updated");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("MetaId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.ToTable("EFMeta");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||
{
|
||||
b.Property<int>("PenaltyId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<string>("AutomatedOffense");
|
||||
|
||||
b.Property<DateTime?>("Expires");
|
||||
|
||||
b.Property<int>("LinkId");
|
||||
|
||||
b.Property<int>("OffenderId");
|
||||
|
||||
b.Property<string>("Offense")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<int>("PunisherId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<DateTime>("When");
|
||||
|
||||
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();
|
||||
|
||||
b.Property<int?>("EFACSnapshotSnapshotId");
|
||||
|
||||
b.Property<float>("X");
|
||||
|
||||
b.Property<float>("Y");
|
||||
|
||||
b.Property<float>("Z");
|
||||
|
||||
b.HasKey("Vector3Id");
|
||||
|
||||
b.HasIndex("EFACSnapshotSnapshotId");
|
||||
|
||||
b.ToTable("Vector3");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
|
||||
.WithMany()
|
||||
.HasForeignKey("CurrentViewAngleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
|
||||
.WithMany()
|
||||
.HasForeignKey("HitDestinationId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
|
||||
.WithMany()
|
||||
.HasForeignKey("HitOriginId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
|
||||
.WithMany()
|
||||
.HasForeignKey("LastStrainAngleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||
.WithMany()
|
||||
.HasForeignKey("AttackerId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
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);
|
||||
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
|
||||
.WithMany()
|
||||
.HasForeignKey("VictimId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
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);
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany()
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics")
|
||||
.WithMany("HitLocations")
|
||||
.HasForeignKey("ClientId", "ServerId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||
{
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
|
||||
.WithMany("Ratings")
|
||||
.HasForeignKey("RatingHistoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||
.WithMany("Children")
|
||||
.HasForeignKey("LinkId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
|
||||
.WithMany()
|
||||
.HasForeignKey("AliasLinkId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
|
||||
.WithMany()
|
||||
.HasForeignKey("CurrentAliasId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||
.WithMany("Meta")
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||
{
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||
.WithMany("ReceivedPenalties")
|
||||
.HasForeignKey("LinkId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
|
||||
.WithMany("ReceivedPenalties")
|
||||
.HasForeignKey("OffenderId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
|
||||
.WithMany("AdministeredPenalties")
|
||||
.HasForeignKey("PunisherId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||
{
|
||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot")
|
||||
.WithMany("PredictedViewAngles")
|
||||
.HasForeignKey("EFACSnapshotSnapshotId");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace SharedLibraryCore.Migrations
|
||||
{
|
||||
public partial class MakeClientIPNullable : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite")
|
||||
{
|
||||
migrationBuilder.Sql(@"PRAGMA foreign_keys = 0;
|
||||
|
||||
CREATE TABLE sqlitestudio_temp_table AS SELECT *
|
||||
FROM EFAlias;
|
||||
|
||||
DROP TABLE EFAlias;
|
||||
|
||||
CREATE TABLE EFAlias (
|
||||
AliasId INTEGER NOT NULL
|
||||
CONSTRAINT PK_EFAlias PRIMARY KEY AUTOINCREMENT,
|
||||
Active INTEGER NOT NULL,
|
||||
DateAdded TEXT NOT NULL,
|
||||
IPAddress INTEGER,
|
||||
LinkId INTEGER NOT NULL,
|
||||
Name TEXT NOT NULL,
|
||||
CONSTRAINT FK_EFAlias_EFAliasLinks_LinkId FOREIGN KEY (
|
||||
LinkId
|
||||
)
|
||||
REFERENCES EFAliasLinks (AliasLinkId) ON DELETE RESTRICT
|
||||
);
|
||||
|
||||
INSERT INTO EFAlias (
|
||||
AliasId,
|
||||
Active,
|
||||
DateAdded,
|
||||
IPAddress,
|
||||
LinkId,
|
||||
Name
|
||||
)
|
||||
SELECT AliasId,
|
||||
Active,
|
||||
DateAdded,
|
||||
IPAddress,
|
||||
LinkId,
|
||||
Name
|
||||
FROM sqlitestudio_temp_table;
|
||||
|
||||
DROP TABLE sqlitestudio_temp_table;
|
||||
|
||||
CREATE INDEX IX_EFAlias_LinkId ON EFAlias (
|
||||
""LinkId""
|
||||
);
|
||||
|
||||
CREATE INDEX IX_EFAlias_IPAddress ON EFAlias(
|
||||
""IPAddress""
|
||||
);
|
||||
|
||||
CREATE INDEX IX_EFAlias_Name ON EFAlias(
|
||||
""Name""
|
||||
);
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
");
|
||||
}
|
||||
else
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "IPAddress",
|
||||
table: "EFAlias",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "IPAddress",
|
||||
table: "EFAlias",
|
||||
nullable: false,
|
||||
oldClrType: typeof(int),
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
@ -317,7 +317,7 @@ namespace SharedLibraryCore.Migrations
|
||||
|
||||
b.Property<DateTime>("DateAdded");
|
||||
|
||||
b.Property<int>("IPAddress");
|
||||
b.Property<int?>("IPAddress");
|
||||
|
||||
b.Property<int>("LinkId");
|
||||
|
||||
|
@ -80,7 +80,6 @@ namespace SharedLibraryCore.Database.Models
|
||||
{
|
||||
{ "_reportCount", 0 }
|
||||
};
|
||||
CurrentAlias = CurrentAlias ?? new EFAlias();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@ -405,7 +404,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
public void OnConnect()
|
||||
{
|
||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||
#if !DEBUG
|
||||
|
||||
if (Name.Length < 3)
|
||||
{
|
||||
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is too short");
|
||||
@ -440,8 +439,6 @@ namespace SharedLibraryCore.Database.Models
|
||||
|
||||
LastConnection = DateTime.UtcNow;
|
||||
Connections += 1;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public async Task OnDisconnect()
|
||||
@ -452,24 +449,11 @@ namespace SharedLibraryCore.Database.Models
|
||||
await CurrentServer.Manager.GetClientService().Update(this);
|
||||
}
|
||||
|
||||
public async Task OnJoin(int ipAddress)
|
||||
public async Task OnJoin(int? ipAddress)
|
||||
{
|
||||
// todo: fix this up
|
||||
var existingAlias = AliasLink.Children
|
||||
.FirstOrDefault(a => a.Name == Name && a.IPAddress == ipAddress);
|
||||
IPAddress = ipAddress;
|
||||
|
||||
if (existingAlias == null)
|
||||
{
|
||||
CurrentServer.Logger.WriteDebug($"Client {this} has connected previously under a different ip/name");
|
||||
|
||||
CurrentAlias = new EFAlias()
|
||||
{
|
||||
IPAddress = ipAddress,
|
||||
Name = Name
|
||||
};
|
||||
}
|
||||
|
||||
await CurrentServer.Manager.GetClientService().Update(this);
|
||||
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
||||
|
||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||
var activePenalties = await CurrentServer.Manager.GetPenaltyService().GetActivePenaltiesAsync(AliasLinkId, ipAddress);
|
||||
@ -519,6 +503,19 @@ namespace SharedLibraryCore.Database.Models
|
||||
Kick($"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Join,
|
||||
Origin = this,
|
||||
Target = this,
|
||||
Owner = CurrentServer
|
||||
};
|
||||
|
||||
CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
@ -557,18 +554,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
public int Score { get; set; }
|
||||
[NotMapped]
|
||||
public bool IsBot { get; set; }
|
||||
//private int _ipaddress;
|
||||
//public override int IPAddress
|
||||
//{
|
||||
// get => _ipaddress;
|
||||
// set => _ipaddress = value;
|
||||
//}
|
||||
//private string _name;
|
||||
//public override string Name
|
||||
//{
|
||||
// get => _name;
|
||||
// set => _name = value;
|
||||
//}
|
||||
|
||||
[NotMapped]
|
||||
public ClientState State { get; set; }
|
||||
[NotMapped]
|
||||
|
@ -313,7 +313,7 @@ namespace SharedLibraryCore
|
||||
public bool RestartRequested { get; set; }
|
||||
|
||||
// Internal
|
||||
protected string IP;
|
||||
public string IP { get; protected set; }
|
||||
protected int Port;
|
||||
protected string FSGame;
|
||||
protected int NextMessage;
|
||||
|
@ -1,15 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedLibraryCore.Database;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using System.Linq.Expressions;
|
||||
using SharedLibraryCore.Objects;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedLibraryCore.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static SharedLibraryCore.Database.Models.EFClient;
|
||||
|
||||
namespace SharedLibraryCore.Services
|
||||
@ -21,55 +17,28 @@ namespace SharedLibraryCore.Services
|
||||
{
|
||||
using (var context = new DatabaseContext())
|
||||
{
|
||||
bool hasExistingAlias = false;
|
||||
// get all aliases by IP
|
||||
var aliases = await context.Aliases
|
||||
.Include(a => a.Link)
|
||||
.Where(a => a.IPAddress == entity.IPAddress)
|
||||
.ToListAsync();
|
||||
|
||||
// see if they have a matching IP + Name but new NetworkId
|
||||
var existingAlias = aliases.FirstOrDefault(a => a.Name == entity.Name);
|
||||
// if existing alias matches link them
|
||||
EFAliasLink aliasLink = existingAlias?.Link;
|
||||
// if no exact matches find the first IP that matches
|
||||
aliasLink = aliasLink ?? aliases.FirstOrDefault()?.Link;
|
||||
// if no exact or IP matches, create new link
|
||||
aliasLink = aliasLink ?? new EFAliasLink()
|
||||
{
|
||||
Active = true,
|
||||
};
|
||||
|
||||
// this has to be set here because we can't evalute it properly later
|
||||
hasExistingAlias = existingAlias != null;
|
||||
|
||||
// if no existing alias create new alias
|
||||
existingAlias = existingAlias ?? new EFAlias()
|
||||
{
|
||||
Active = true,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
IPAddress = entity.IPAddress,
|
||||
Link = aliasLink,
|
||||
Name = entity.Name,
|
||||
};
|
||||
|
||||
var client = new EFClient()
|
||||
{
|
||||
Active = true,
|
||||
// set the level to the level of the existing client if they have the same IP + Name but new NetworkId
|
||||
// fixme: issues?
|
||||
Level = hasExistingAlias ?
|
||||
(await context.Clients.Where(c => c.AliasLinkId == existingAlias.LinkId)
|
||||
.OrderByDescending(c => c.Level)
|
||||
.FirstOrDefaultAsync())?.Level ?? Permission.User :
|
||||
Permission.User,
|
||||
Level = Permission.User,
|
||||
FirstConnection = DateTime.UtcNow,
|
||||
Connections = 1,
|
||||
LastConnection = DateTime.UtcNow,
|
||||
Masked = false,
|
||||
NetworkId = entity.NetworkId,
|
||||
AliasLink = aliasLink,
|
||||
CurrentAlias = existingAlias,
|
||||
AliasLink = new EFAliasLink()
|
||||
{
|
||||
Active = false
|
||||
},
|
||||
};
|
||||
|
||||
client.CurrentAlias = new Alias()
|
||||
{
|
||||
Name = entity.Name,
|
||||
Link = client.AliasLink,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
// the first time a client is created, we may not have their ip,
|
||||
// so we create a temporary alias
|
||||
Active = false
|
||||
};
|
||||
|
||||
context.Clients.Add(client);
|
||||
@ -79,6 +48,101 @@ namespace SharedLibraryCore.Services
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateAlias(EFClient entity)
|
||||
{
|
||||
using (var context = new DatabaseContext())
|
||||
{
|
||||
context.Attach(entity);
|
||||
|
||||
string name = entity.Name;
|
||||
int? ip = entity.IPAddress;
|
||||
|
||||
bool hasExistingAlias = false;
|
||||
|
||||
// get all aliases by IP
|
||||
var aliases = await context.Aliases
|
||||
.Include(a => a.Link)
|
||||
.Where(a => a.IPAddress != null && a.IPAddress == ip)
|
||||
.ToListAsync();
|
||||
|
||||
// see if they have a matching IP + Name but new NetworkId
|
||||
var existingAlias = aliases.FirstOrDefault(a => a.Name == name);
|
||||
// if existing alias matches link them
|
||||
EFAliasLink aliasLink = existingAlias?.Link;
|
||||
// if no exact matches find the first IP that matches
|
||||
aliasLink = aliasLink ?? aliases.FirstOrDefault()?.Link;
|
||||
// if no exact or IP matches, create new link
|
||||
aliasLink = aliasLink ?? new EFAliasLink();
|
||||
|
||||
// this has to be set here because we can't evalute it properly later
|
||||
hasExistingAlias = existingAlias != null;
|
||||
|
||||
if (hasExistingAlias && !entity.AliasLink.Active)
|
||||
{
|
||||
// we want to delete the temporary alias
|
||||
context.Entry(entity.CurrentAlias).State = EntityState.Deleted;
|
||||
entity.CurrentAlias = null;
|
||||
|
||||
// we want to delete the temporary alias link
|
||||
context.Entry(entity.AliasLink).State = EntityState.Deleted;
|
||||
entity.AliasLink = null;
|
||||
|
||||
// they have an existing alias so assign it
|
||||
entity.CurrentAlias = existingAlias;
|
||||
entity.AliasLink = aliasLink;
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// update the temporary alias to permanent one
|
||||
else if (!entity.AliasLink.Active)
|
||||
{
|
||||
// we want to track the current alias and link
|
||||
var alias = context.Update(entity.CurrentAlias).Entity;
|
||||
var _aliasLink = context.Update(entity.AliasLink).Entity;
|
||||
|
||||
alias.Active = true;
|
||||
alias.IPAddress = ip;
|
||||
alias.Name = name;
|
||||
_aliasLink.Active = true;
|
||||
|
||||
existingAlias = alias;
|
||||
aliasLink = _aliasLink;
|
||||
}
|
||||
|
||||
// if no existing alias create new alias
|
||||
existingAlias = existingAlias ?? new EFAlias()
|
||||
{
|
||||
DateAdded = DateTime.UtcNow,
|
||||
IPAddress = ip,
|
||||
Link = aliasLink,
|
||||
Name = name,
|
||||
};
|
||||
|
||||
var iqExistingPermission = context.Clients.Where(c => c.AliasLinkId == existingAlias.LinkId)
|
||||
.OrderByDescending(client => client.Level)
|
||||
.Select(c => new EFClient() { Level = c.Level });
|
||||
|
||||
entity.Level = hasExistingAlias ?
|
||||
(await iqExistingPermission.FirstOrDefaultAsync())?.Level ?? Permission.User :
|
||||
Permission.User;
|
||||
#if DEBUG
|
||||
string sql = iqExistingPermission.AsQueryable().ToSql();
|
||||
#endif
|
||||
|
||||
if (entity.CurrentAlias != existingAlias ||
|
||||
entity.AliasLink != aliasLink)
|
||||
{
|
||||
entity.CurrentAlias = existingAlias;
|
||||
entity.AliasLink = aliasLink;
|
||||
|
||||
context.Update(entity);
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<EFClient> Delete(EFClient entity)
|
||||
{
|
||||
using (var context = new DatabaseContext())
|
||||
@ -132,13 +196,17 @@ namespace SharedLibraryCore.Services
|
||||
var foundClient = await iqClient.FirstOrDefaultAsync();
|
||||
|
||||
if (foundClient == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foundClient.Client.LinkedAccounts = new Dictionary<int, long>();
|
||||
// todo: find out the best way to do this
|
||||
// I'm doing this here because I don't know the best way to have multiple awaits in the query
|
||||
foreach (var linked in foundClient.LinkedAccounts)
|
||||
{
|
||||
foundClient.Client.LinkedAccounts.Add(linked.ClientId, linked.NetworkId);
|
||||
}
|
||||
|
||||
return foundClient.Client;
|
||||
}
|
||||
@ -168,7 +236,7 @@ namespace SharedLibraryCore.Services
|
||||
var client = context.Clients
|
||||
.Include(c => c.AliasLink)
|
||||
.Include(c => c.CurrentAlias)
|
||||
.Single(e => e.ClientId == entity.ClientId);
|
||||
.First(e => e.ClientId == entity.ClientId);
|
||||
|
||||
// if their level has been changed
|
||||
if (entity.Level != client.Level)
|
||||
@ -191,7 +259,7 @@ namespace SharedLibraryCore.Services
|
||||
{
|
||||
client.CurrentAlias = new EFAlias()
|
||||
{
|
||||
Active = true,
|
||||
Active = entity.CurrentAlias.IPAddress.HasValue ? true : false,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
IPAddress = entity.CurrentAlias.IPAddress,
|
||||
Name = entity.CurrentAlias.Name,
|
||||
@ -202,6 +270,8 @@ namespace SharedLibraryCore.Services
|
||||
else
|
||||
{
|
||||
client.CurrentAliasId = entity.CurrentAliasId;
|
||||
client.IPAddress = entity.IPAddress;
|
||||
client.Name = entity.Name;
|
||||
}
|
||||
|
||||
// set remaining non-navigation properties that may have been updated
|
||||
@ -219,7 +289,10 @@ namespace SharedLibraryCore.Services
|
||||
|
||||
// this is set so future updates don't trigger a new alias add
|
||||
if (entity.CurrentAlias.AliasId == 0)
|
||||
{
|
||||
entity.CurrentAlias.AliasId = client.CurrentAlias.AliasId;
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
@ -228,24 +301,27 @@ namespace SharedLibraryCore.Services
|
||||
public async Task<IList<EFClient>> GetOwners()
|
||||
{
|
||||
using (var context = new DatabaseContext())
|
||||
{
|
||||
return await context.Clients
|
||||
.Where(c => c.Level == Permission.Owner)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IList<ClientInfo>> GetPrivilegedClients()
|
||||
public async Task<List<EFClient>> GetPrivilegedClients()
|
||||
{
|
||||
using (var context = new DatabaseContext(disableTracking: true))
|
||||
{
|
||||
var iqClients = from client in context.Clients
|
||||
where client.Level >= Permission.Trusted
|
||||
where client.Active
|
||||
select new ClientInfo()
|
||||
select new EFClient()
|
||||
{
|
||||
CurrentAlias = client.CurrentAlias,
|
||||
ClientId = client.ClientId,
|
||||
Name = client.CurrentAlias.Name,
|
||||
LinkId = client.AliasLinkId,
|
||||
Level = client.Level
|
||||
Level = client.Level,
|
||||
Password = client.Password,
|
||||
PasswordSalt = client.PasswordSalt
|
||||
};
|
||||
|
||||
#if DEBUG == true
|
||||
@ -294,20 +370,16 @@ namespace SharedLibraryCore.Services
|
||||
public async Task<int> GetTotalClientsAsync()
|
||||
{
|
||||
using (var context = new DatabaseContext(true))
|
||||
{
|
||||
return await context.Clients
|
||||
.CountAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<EFClient> CreateProxy()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalPlayTime()
|
||||
{
|
||||
using (var context = new DatabaseContext(true))
|
||||
return await context.Clients.SumAsync(c => c.TotalConnectionTime);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ namespace SharedLibraryCore.Services
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<EFPenalty>> GetActivePenaltiesAsync(int linkId, int ip = 0)
|
||||
public async Task<List<EFPenalty>> GetActivePenaltiesAsync(int linkId, int? ip = null)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
@ -221,7 +221,7 @@ namespace SharedLibraryCore.Services
|
||||
{
|
||||
var iqPenalties = context.Penalties
|
||||
.Where(p => p.LinkId == linkId ||
|
||||
p.Link.Children.Any(a => a.IPAddress == ip))
|
||||
ip.HasValue ? p.Link.Children.Any(a => a.IPAddress == ip) : false)
|
||||
.Where(p => p.Type == Penalty.PenaltyType.TempBan ||
|
||||
p.Type == Penalty.PenaltyType.Ban ||
|
||||
p.Type == Penalty.PenaltyType.Flag)
|
||||
|
@ -1,21 +1,18 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using SharedLibraryCore.Objects;
|
||||
using static SharedLibraryCore.Server;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using static SharedLibraryCore.Server;
|
||||
|
||||
namespace SharedLibraryCore
|
||||
{
|
||||
@ -28,14 +25,20 @@ namespace SharedLibraryCore
|
||||
#endif
|
||||
public static Encoding EncodingType;
|
||||
public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary<string, string>());
|
||||
public static EFClient IW4MAdminClient(Server server = null) => new EFClient()
|
||||
public static EFClient IW4MAdminClient(Server server = null)
|
||||
{
|
||||
ClientId = 1,
|
||||
State = EFClient.ClientState.Connected,
|
||||
Level = EFClient.Permission.Console,
|
||||
CurrentServer = server,
|
||||
Name = "IW4MAdmin"
|
||||
};
|
||||
return new EFClient()
|
||||
{
|
||||
ClientId = 1,
|
||||
State = EFClient.ClientState.Connected,
|
||||
Level = EFClient.Permission.Console,
|
||||
CurrentServer = server,
|
||||
CurrentAlias = new EFAlias()
|
||||
{
|
||||
Name = "IW4MAdmin"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static string HttpRequest(string location, string header, string headerValue)
|
||||
{
|
||||
@ -64,7 +67,9 @@ namespace SharedLibraryCore
|
||||
public static String RemoveWords(this string str, int num)
|
||||
{
|
||||
if (str == null || str.Length == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
String newStr = String.Empty;
|
||||
String[] tmp = str.Split(' ');
|
||||
@ -72,7 +77,9 @@ namespace SharedLibraryCore
|
||||
for (int i = 0; i < tmp.Length; i++)
|
||||
{
|
||||
if (i >= num)
|
||||
{
|
||||
newStr += tmp[i] + ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return newStr;
|
||||
@ -105,9 +112,13 @@ namespace SharedLibraryCore
|
||||
String lookingFor = str.ToLower();
|
||||
|
||||
for (EFClient.Permission Perm = EFClient.Permission.User; Perm < EFClient.Permission.Console; Perm++)
|
||||
{
|
||||
if (lookingFor.Contains(Perm.ToString().ToLower())
|
||||
|| lookingFor.Contains(CurrentLocalization.LocalizationIndex[$"GLOBAL_PERMISSION_{Perm.ToString().ToUpper()}"].ToLower()))
|
||||
{
|
||||
return Perm;
|
||||
}
|
||||
}
|
||||
|
||||
return EFClient.Permission.Banned;
|
||||
}
|
||||
@ -120,7 +131,10 @@ namespace SharedLibraryCore
|
||||
public static String StripColors(this string str)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
str = Regex.Replace(str, @"(\^+((?![a-z]|[A-Z]).){0,1})+", "");
|
||||
string str2 = Regex.Match(str, @"(^\/+.*$)|(^.*\/+$)")
|
||||
.Value
|
||||
@ -161,7 +175,10 @@ namespace SharedLibraryCore
|
||||
return $"^{colorCode}{localizedLevel ?? level.ToString()}";
|
||||
}
|
||||
|
||||
public static string ToLocalizedLevelName(this EFClient.Permission perm) => CurrentLocalization.LocalizationIndex[$"GLOBAL_PERMISSION_{perm.ToString().ToUpper()}"];
|
||||
public static string ToLocalizedLevelName(this EFClient.Permission perm)
|
||||
{
|
||||
return CurrentLocalization.LocalizationIndex[$"GLOBAL_PERMISSION_{perm.ToString().ToUpper()}"];
|
||||
}
|
||||
|
||||
public static String ProcessMessageToken(this Server server, IList<Helpers.MessageToken> tokens, String str)
|
||||
{
|
||||
@ -174,7 +191,9 @@ namespace SharedLibraryCore
|
||||
var found = tokens.FirstOrDefault(t => t.Name.ToLower() == Identifier.ToLower());
|
||||
|
||||
if (found != null)
|
||||
{
|
||||
str = str.Replace(Match, found.Process(server));
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
@ -245,11 +264,17 @@ namespace SharedLibraryCore
|
||||
{
|
||||
str = str.Substring(0, Math.Min(str.Length, 16));
|
||||
if (Int64.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
var bot = Regex.Match(str, @"bot[0-9]+").Value;
|
||||
if (!string.IsNullOrEmpty(bot))
|
||||
{
|
||||
// should set their GUID to the negation of their 1 based index (-1 - -18)
|
||||
return -(Convert.ToInt64(bot.Substring(3)) + 1);
|
||||
}
|
||||
|
||||
return long.MinValue;
|
||||
}
|
||||
|
||||
@ -260,9 +285,9 @@ namespace SharedLibraryCore
|
||||
return ip == null ? int.MaxValue : BitConverter.ToInt32(ip.GetAddressBytes(), 0);
|
||||
}
|
||||
|
||||
public static string ConvertIPtoString(this int ip)
|
||||
public static string ConvertIPtoString(this int? ip)
|
||||
{
|
||||
return new System.Net.IPAddress(BitConverter.GetBytes(ip)).ToString();
|
||||
return !ip.HasValue ? "" : new System.Net.IPAddress(BitConverter.GetBytes(ip.Value)).ToString();
|
||||
}
|
||||
|
||||
public static String GetTimePassed(DateTime start)
|
||||
@ -282,19 +307,28 @@ namespace SharedLibraryCore
|
||||
if (Elapsed.TotalMinutes < 120)
|
||||
{
|
||||
if (Elapsed.TotalMinutes < 1.5)
|
||||
{
|
||||
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_MINUTES"]}{ago}";
|
||||
}
|
||||
|
||||
return Math.Round(Elapsed.TotalMinutes, 0) + $" {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_MINUTES"]}{ago}";
|
||||
}
|
||||
if (Elapsed.TotalHours <= 24)
|
||||
{
|
||||
if (Elapsed.TotalHours < 1.5)
|
||||
{
|
||||
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_HOURS"]}{ago}";
|
||||
}
|
||||
|
||||
return Math.Round(Elapsed.TotalHours, 0) + $" { CurrentLocalization.LocalizationIndex["GLOBAL_TIME_HOURS"]}{ago}";
|
||||
}
|
||||
if (Elapsed.TotalDays <= 90)
|
||||
{
|
||||
if (Elapsed.TotalDays < 1.5)
|
||||
{
|
||||
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_DAYS"]}{ago}";
|
||||
}
|
||||
|
||||
return Math.Round(Elapsed.TotalDays, 0) + $" {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_DAYS"]}{ago}";
|
||||
}
|
||||
if (Elapsed.TotalDays <= 365)
|
||||
@ -310,19 +344,39 @@ namespace SharedLibraryCore
|
||||
public static Game GetGame(string gameName)
|
||||
{
|
||||
if (gameName.Contains("IW4"))
|
||||
{
|
||||
return Game.IW4;
|
||||
}
|
||||
|
||||
if (gameName.Contains("CoD4"))
|
||||
{
|
||||
return Game.IW3;
|
||||
}
|
||||
|
||||
if (gameName.Contains("COD_WaW"))
|
||||
{
|
||||
return Game.T4;
|
||||
}
|
||||
|
||||
if (gameName.Contains("COD_T5_S"))
|
||||
{
|
||||
return Game.T5;
|
||||
}
|
||||
|
||||
if (gameName.Contains("T5M"))
|
||||
{
|
||||
return Game.T5M;
|
||||
}
|
||||
|
||||
if (gameName.Contains("IW5"))
|
||||
{
|
||||
return Game.IW5;
|
||||
}
|
||||
|
||||
if (gameName.Contains("COD_T6_S"))
|
||||
{
|
||||
return Game.T6M;
|
||||
}
|
||||
|
||||
return Game.UKN;
|
||||
}
|
||||
@ -337,7 +391,9 @@ namespace SharedLibraryCore
|
||||
var expressionMatch = Regex.Match(input, @"([0-9]+)(\w+)");
|
||||
|
||||
if (!expressionMatch.Success) // fallback to default tempban length of 1 hour
|
||||
{
|
||||
return new TimeSpan(1, 0, 0);
|
||||
}
|
||||
|
||||
char lengthDenote = expressionMatch.Groups[2].ToString()[0];
|
||||
int length = Int32.Parse(expressionMatch.Groups[1].ToString());
|
||||
@ -377,52 +433,42 @@ namespace SharedLibraryCore
|
||||
var loc = CurrentLocalization.LocalizationIndex;
|
||||
|
||||
if (span.TotalMinutes < 60)
|
||||
{
|
||||
return $"{span.Minutes} {loc["GLOBAL_TIME_MINUTES"]}";
|
||||
}
|
||||
else if (span.Hours >= 1 && span.TotalHours < 24)
|
||||
{
|
||||
return $"{span.Hours} {loc["GLOBAL_TIME_HOURS"]}";
|
||||
}
|
||||
else if (span.TotalDays >= 1 && span.TotalDays < 7)
|
||||
{
|
||||
return $"{span.Days} {loc["GLOBAL_TIME_DAYS"]}";
|
||||
}
|
||||
else if (span.TotalDays >= 7 && span.TotalDays < 90)
|
||||
{
|
||||
return $"{Math.Round(span.Days / 7.0, 0)} {loc["GLOBAL_TIME_WEEKS"]}";
|
||||
}
|
||||
else if (span.TotalDays >= 90 && span.TotalDays < 365)
|
||||
{
|
||||
return $"{Math.Round(span.Days / 30.0, 0)} {loc["GLOBAL_TIME_MONTHS"]}";
|
||||
}
|
||||
else if (span.TotalDays >= 365 && span.TotalDays < 36500)
|
||||
{
|
||||
return $"{Math.Round(span.Days / 365.0, 0)} {loc["GLOBAL_TIME_YEARS"]}";
|
||||
}
|
||||
else if (span.TotalDays >= 36500)
|
||||
{
|
||||
return loc["GLOBAL_TIME_FOREVER"];
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
public static EFClient AsEFClient(this Database.Models.EFClient client)
|
||||
public static bool IsPrivileged(this EFClient p)
|
||||
{
|
||||
return client == null ? null : new EFClient()
|
||||
{
|
||||
Active = client.Active,
|
||||
AliasLink = client.AliasLink,
|
||||
AliasLinkId = client.AliasLinkId,
|
||||
ClientId = client.ClientId,
|
||||
ClientNumber = -1,
|
||||
FirstConnection = client.FirstConnection,
|
||||
Connections = client.Connections,
|
||||
NetworkId = client.NetworkId,
|
||||
TotalConnectionTime = client.TotalConnectionTime,
|
||||
Masked = client.Masked,
|
||||
Name = client.CurrentAlias.Name,
|
||||
IPAddress = client.CurrentAlias.IPAddress,
|
||||
Level = client.Level,
|
||||
LastConnection = client.LastConnection == DateTime.MinValue ? DateTime.UtcNow : client.LastConnection,
|
||||
CurrentAlias = client.CurrentAlias,
|
||||
CurrentAliasId = client.CurrentAlias.AliasId,
|
||||
// todo: make sure this is up to date
|
||||
IsBot = client.IPAddress == int.MinValue,
|
||||
Password = client.Password,
|
||||
PasswordSalt = client.PasswordSalt
|
||||
};
|
||||
return p.Level > EFClient.Permission.User;
|
||||
}
|
||||
|
||||
public static bool IsPrivileged(this EFClient p) => p.Level > EFClient.Permission.User;
|
||||
|
||||
public static bool PromptBool(string question)
|
||||
{
|
||||
Console.Write($"{question}? [y/n]: ");
|
||||
@ -474,7 +520,9 @@ namespace SharedLibraryCore
|
||||
int.TryParse(lineSplit[cIDPos].Trim(), out pID);
|
||||
|
||||
if (pID == -1) // special case similar to mod_suicide
|
||||
{
|
||||
int.TryParse(lineSplit[2], out pID);
|
||||
}
|
||||
|
||||
return pID;
|
||||
}
|
||||
@ -489,7 +537,9 @@ namespace SharedLibraryCore
|
||||
{
|
||||
dict = new Dictionary<string, string>();
|
||||
for (int i = 0; i < values.Length; i += 2)
|
||||
{
|
||||
dict.Add(values[i], values[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
@ -518,15 +568,30 @@ namespace SharedLibraryCore
|
||||
return cmdLine.Length > 1 ? cmdLine[1] : cmdLine[0];
|
||||
}
|
||||
|
||||
public static string ToBase64UrlSafeString(this string src) => Convert.ToBase64String(src.Select(c => Convert.ToByte(c)).ToArray()).Replace('+', '-').Replace('/', '_');
|
||||
public static string ToBase64UrlSafeString(this string src)
|
||||
{
|
||||
return Convert.ToBase64String(src.Select(c => Convert.ToByte(c)).ToArray()).Replace('+', '-').Replace('/', '_');
|
||||
}
|
||||
|
||||
public static Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName) => server.RconParser.GetDvarAsync<T>(server.RemoteConnection, dvarName);
|
||||
public static Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName)
|
||||
{
|
||||
return server.RconParser.GetDvarAsync<T>(server.RemoteConnection, dvarName);
|
||||
}
|
||||
|
||||
public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue) => server.RconParser.SetDvarAsync(server.RemoteConnection, dvarName, dvarValue);
|
||||
public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue)
|
||||
{
|
||||
return server.RconParser.SetDvarAsync(server.RemoteConnection, dvarName, dvarValue);
|
||||
}
|
||||
|
||||
public static async Task<string[]> ExecuteCommandAsync(this Server server, string commandName) => await server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName);
|
||||
public static async Task<string[]> ExecuteCommandAsync(this Server server, string commandName)
|
||||
{
|
||||
return await server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName);
|
||||
}
|
||||
|
||||
public static Task<List<EFClient>> GetStatusAsync(this Server server) => server.RconParser.GetStatusAsync(server.RemoteConnection);
|
||||
public static Task<List<EFClient>> GetStatusAsync(this Server server)
|
||||
{
|
||||
return server.RconParser.GetStatusAsync(server.RemoteConnection);
|
||||
}
|
||||
|
||||
public static async Task<Dictionary<string, string>> GetInfoAsync(this Server server)
|
||||
{
|
||||
@ -535,7 +600,10 @@ namespace SharedLibraryCore
|
||||
{
|
||||
response = await server.RemoteConnection.SendQueryAsync(RCon.StaticHelpers.QueryType.GET_INFO);
|
||||
if (response.Length == 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
await Task.Delay(RCon.StaticHelpers.FloodProtectionInterval);
|
||||
}
|
||||
return response.FirstOrDefault(r => r[0] == '\\')?.DictionaryFromKeyValue();
|
||||
@ -548,7 +616,10 @@ namespace SharedLibraryCore
|
||||
return double.Parse(version) / 1000.0;
|
||||
}
|
||||
|
||||
public static string GetVersionAsString() => Assembly.GetCallingAssembly().GetName().Version.ToString();
|
||||
public static string GetVersionAsString()
|
||||
{
|
||||
return Assembly.GetCallingAssembly().GetName().Version.ToString();
|
||||
}
|
||||
|
||||
#if DEBUG == true
|
||||
|
||||
|
@ -57,13 +57,6 @@ namespace WebfrontCore.Controllers
|
||||
Client.ClientId = Convert.ToInt32(base.User.Claims.First(c => c.Type == ClaimTypes.Sid).Value);
|
||||
Client.Level = (EFClient.Permission)Enum.Parse(typeof(EFClient.Permission), User.Claims.First(c => c.Type == ClaimTypes.Role).Value);
|
||||
Client.CurrentAlias = new EFAlias() { Name = User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value };
|
||||
var stillExists = Manager.GetPrivilegedClients()[Client.ClientId];
|
||||
|
||||
// this happens if their level has been updated
|
||||
if (stillExists.Level != Client.Level)
|
||||
{
|
||||
Client.Level = stillExists.Level;
|
||||
}
|
||||
}
|
||||
|
||||
catch (InvalidOperationException)
|
||||
@ -78,11 +71,13 @@ namespace WebfrontCore.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
// give the local host full access
|
||||
else
|
||||
{
|
||||
Client.ClientId = 1;
|
||||
Client.Level = EFClient.Permission.Console;
|
||||
Client.CurrentAlias = new EFAlias() { Name = "IW4MAdmin" };
|
||||
Authorized = true;
|
||||
}
|
||||
|
||||
Authorized = Client.ClientId >= 0;
|
||||
|
@ -121,7 +121,7 @@ namespace WebfrontCore.Controllers
|
||||
{
|
||||
var admins = (await Manager.GetClientService().GetPrivilegedClients())
|
||||
.OrderByDescending(a => a.Level)
|
||||
.GroupBy(a => a.LinkId).Select(a => a.First());
|
||||
.GroupBy(a => a.AliasLinkId).Select(a => a.First());
|
||||
|
||||
var adminsDict = new Dictionary<EFClient.Permission, IList<ClientInfo>>();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model Dictionary<SharedLibraryCore.Objects.Player.Permission, IList<SharedLibraryCore.Dtos.ClientInfo>>
|
||||
@model Dictionary<SharedLibraryCore.Database.Models.EFClient.Permission, IList<SharedLibraryCore.Dtos.ClientInfo>>
|
||||
|
||||
<h4 class="pb-2 text-center ">@ViewBag.Title</h4>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user