strip drive letter on gamelog server if running on linux

strip undecodable chacters from gamelog server log file
finish re work on alias add/update ( I think)
This commit is contained in:
RaidMax 2019-04-05 21:15:17 -05:00
parent 8ab89e113d
commit 863ba8b096
14 changed files with 157 additions and 109 deletions

3
.gitignore vendored
View File

@ -232,4 +232,5 @@ bootstrap-custom.min.css
launchSettings.json launchSettings.json
/VpnDetectionPrivate.js /VpnDetectionPrivate.js
/Plugins/ScriptPlugins/VpnDetectionPrivate.js /Plugins/ScriptPlugins/VpnDetectionPrivate.js
**/Master/env_master **/Master/env_master
/GameLogServer/log_env

View File

@ -36,8 +36,7 @@ namespace IW4MAdmin
override public async Task OnClientConnected(EFClient clientFromLog) override public async Task OnClientConnected(EFClient clientFromLog)
{ {
Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved"); Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved");
Clients[clientFromLog.ClientNumber] = new EFClient();
try try
{ {
EFClient client = await Manager.GetClientService().GetUnique(clientFromLog.NetworkId); EFClient client = await Manager.GetClientService().GetUnique(clientFromLog.NetworkId);
@ -71,7 +70,7 @@ namespace IW4MAdmin
Clients[client.ClientNumber] = client; Clients[client.ClientNumber] = client;
client.State = EFClient.ClientState.Connected; client.State = ClientState.Connected;
#if DEBUG == true #if DEBUG == true
Logger.WriteDebug($"End PreConnect for {client}"); Logger.WriteDebug($"End PreConnect for {client}");
#endif #endif
@ -207,7 +206,14 @@ namespace IW4MAdmin
var existingClient = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin)); var existingClient = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin));
// they're already connected
if (existingClient != null)
{
return false;
}
CONNECT: CONNECT:
// we can go ahead and put them in
if (Clients[E.Origin.ClientNumber] == null) if (Clients[E.Origin.ClientNumber] == null)
{ {
#if DEBUG == true #if DEBUG == true
@ -229,17 +235,12 @@ namespace IW4MAdmin
} }
// for some reason there's still a client in the spot // for some reason there's still a client in the spot
else if (existingClient == null) else
{ {
Logger.WriteWarning($"{E.Origin} is connecteding but {Clients[E.Origin.ClientNumber]} is currently in that client slot"); Logger.WriteWarning($"{E.Origin} is connecteding but {Clients[E.Origin.ClientNumber]} is currently in that client slot");
await OnClientDisconnected(Clients[E.Origin.ClientNumber]); await OnClientDisconnected(Clients[E.Origin.ClientNumber]);
goto CONNECT; goto CONNECT;
} }
else
{
return false;
}
} }
else if (E.Type == GameEvent.EventType.Flag) else if (E.Type == GameEvent.EventType.Flag)

View File

@ -17,7 +17,7 @@
<SuppressCollectPythonCloudServiceFiles>true</SuppressCollectPythonCloudServiceFiles> <SuppressCollectPythonCloudServiceFiles>true</SuppressCollectPythonCloudServiceFiles>
<Name>GameLogServer</Name> <Name>GameLogServer</Name>
<RootNamespace>GameLogServer</RootNamespace> <RootNamespace>GameLogServer</RootNamespace>
<InterpreterId>MSBuild|env|$(MSBuildProjectFullPath)</InterpreterId> <InterpreterId>MSBuild|log_env|$(MSBuildProjectFullPath)</InterpreterId>
<EnableNativeCodeDebugging>False</EnableNativeCodeDebugging> <EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
<Environment>DEBUG=True</Environment> <Environment>DEBUG=True</Environment>
</PropertyGroup> </PropertyGroup>
@ -50,7 +50,6 @@
<Folder Include="GameLogServer\" /> <Folder Include="GameLogServer\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="requirements.txt" />
<None Include="Stable.pubxml" /> <None Include="Stable.pubxml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -63,6 +62,18 @@
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable> <PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>X64</Architecture> <Architecture>X64</Architecture>
</Interpreter> </Interpreter>
<Interpreter Include="log_env\">
<Id>log_env</Id>
<Version>3.6</Version>
<Description>log_env (Python 3.6 (64-bit))</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>X64</Architecture>
</Interpreter>
</ItemGroup>
<ItemGroup>
<Content Include="requirements.txt" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.Web.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.Web.targets" />
<!-- Specify pre- and post-build commands in the BeforeBuild and <!-- Specify pre- and post-build commands in the BeforeBuild and

View File

@ -6,8 +6,7 @@ class LogReader(object):
def __init__(self): def __init__(self):
self.log_file_sizes = {} self.log_file_sizes = {}
# (if the time between checks is greater, ignore ) - in seconds # (if the time between checks is greater, ignore ) - in seconds
# self.max_file_time_change = 60 self.max_file_time_change = 30
self.max_file_time_change = 10
def read_file(self, path): def read_file(self, path):
# this removes old entries that are no longer valid # this removes old entries that are no longer valid
@ -17,33 +16,34 @@ class LogReader(object):
print('could not clear old logs') print('could not clear old logs')
print(e) print(e)
if os.name != 'nt':
path = re.sub(r'^[A-Z]\:', '', path)
path = re.sub(r'\\+', '/', path)
# prevent traversing directories # prevent traversing directories
if re.search('r^.+\.\.\\.+$', path): if re.search('r^.+\.\.\\.+$', path):
return False return False
# must be a valid log path and log file # must be a valid log path and log file
if not re.search(r'^.+[\\|\/](.+)[\\|\/].+.log$', path): if not re.search(r'^.+[\\|\/](.+)[\\|\/].+.log$', path):
return False return False
# set the initial size to the current file size
file_size = 0
# this is the first time the log has been requested # get the new file size
if path not in self.log_file_sizes:
self.log_file_sizes[path] = {
'length' : self.file_length(path),
'read': time.time()
}
return ''
# grab the previous values
last_length = self.log_file_sizes[path]['length']
# the file is being tracked already
new_file_size = self.file_length(path) new_file_size = self.file_length(path)
# the log size was unable to be read (probably the wrong path) # the log size was unable to be read (probably the wrong path)
if new_file_size < 0: if new_file_size < 0:
return False return False
# this is the first time the log has been requested
if path not in self.log_file_sizes:
self.log_file_sizes[path] = {
'length' : new_file_size,
'read': time.time()
}
return ''
# grab the previous values
last_length = self.log_file_sizes[path]['length']
file_size_difference = new_file_size - last_length file_size_difference = new_file_size - last_length
# update the new size and actually read the data # update the new size and actually read the data
@ -61,7 +61,8 @@ class LogReader(object):
file_handle.seek(-length, 2) file_handle.seek(-length, 2)
file_data = file_handle.read(length) file_data = file_handle.read(length)
file_handle.close() file_handle.close()
return file_data.decode('utf-8') # using ignore errors omits the pesky 0xb2 bytes we're reading in for some reason
return file_data.decode('utf-8', errors='ignore')
except Exception as e: except Exception as e:
print('could not read the log file at {0}, wanted to read {1} bytes'.format(path, length)) print('could not read the log file at {0}, wanted to read {1} bytes'.format(path, length))
print(e) print(e)

View File

@ -6,7 +6,6 @@ class LogResource(Resource):
def get(self, path): def get(self, path):
path = urlsafe_b64decode(path).decode('utf-8') path = urlsafe_b64decode(path).decode('utf-8')
log_info = reader.read_file(path) log_info = reader.read_file(path)
print(log_info)
return { return {
'success' : log_info is not False, 'success' : log_info is not False,

View File

@ -1,29 +1,29 @@
from flask_restful import Resource #from flask_restful import Resource
from flask import request #from flask import request
import requests #import requests
import os #import os
import subprocess #import subprocess
import re #import re
def get_pid_of_server_windows(port): #def get_pid_of_server_windows(port):
process = subprocess.Popen('netstat -aon', shell=True, stdout=subprocess.PIPE) # process = subprocess.Popen('netstat -aon', shell=True, stdout=subprocess.PIPE)
output = process.communicate()[0] # output = process.communicate()[0]
matches = re.search(' *(UDP) +([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}):'+ str(port) + ' +[^\w]*([0-9]+)', output.decode('utf-8')) # matches = re.search(' *(UDP) +([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}):'+ str(port) + ' +[^\w]*([0-9]+)', output.decode('utf-8'))
if matches is not None: # if matches is not None:
return matches.group(3) # return matches.group(3)
else: # else:
return 0 # return 0
class RestartResource(Resource): #class RestartResource(Resource):
def get(self): # def get(self):
try: # try:
response = requests.get('http://' + request.remote_addr + ':1624/api/restartapproved') # response = requests.get('http://' + request.remote_addr + ':1624/api/restartapproved')
if response.status_code == 200: # if response.status_code == 200:
pid = get_pid_of_server_windows(response.json()['port']) # pid = get_pid_of_server_windows(response.json()['port'])
subprocess.check_output("Taskkill /PID %s /F" % pid) # subprocess.check_output("Taskkill /PID %s /F" % pid)
else: # else:
return {}, 400 # return {}, 400
except Exception as e: # except Exception as e:
print(e) # print(e)
return {}, 500 # return {}, 500
return {}, 200 # return {}, 200

View File

@ -1,7 +1,7 @@
from flask import Flask from flask import Flask
from flask_restful import Api from flask_restful import Api
from .log_resource import LogResource from .log_resource import LogResource
from .restart_resource import RestartResource #from .restart_resource import RestartResource
import logging import logging
app = Flask(__name__) app = Flask(__name__)
@ -11,4 +11,4 @@ def init():
log.setLevel(logging.ERROR) log.setLevel(logging.ERROR)
api = Api(app) api = Api(app)
api.add_resource(LogResource, '/log/<string:path>') api.add_resource(LogResource, '/log/<string:path>')
api.add_resource(RestartResource, '/restart') #api.add_resource(RestartResource, '/restart')

View File

@ -1,26 +1,12 @@
aniso8601==3.0.2 aniso8601==6.0.0
APScheduler==3.5.3 Click==7.0
certifi==2018.10.15
chardet==3.0.4
click==6.7
Flask==1.0.2 Flask==1.0.2
Flask-JWT==0.3.2 Flask-RESTful==0.3.7
Flask-JWT-Extended==3.8.1 itsdangerous==1.1.0
Flask-RESTful==0.3.6
idna==2.7
itsdangerous==0.24
Jinja2==2.10 Jinja2==2.10
MarkupSafe==1.0 MarkupSafe==1.1.1
marshmallow==3.0.0b8 pip==10.0.1
pip==9.0.3 pytz==2018.9
psutil==5.4.8 setuptools==39.0.1
pygal==2.4.0 six==1.12.0
PyJWT==1.4.2 Werkzeug==0.15.2
pytz==2018.7
requests==2.20.0
setuptools==40.5.0
six==1.11.0
timeago==1.0.8
tzlocal==1.5.1
urllib3==1.24
Werkzeug==0.14.1

View File

@ -51,7 +51,6 @@ namespace IW4MAdmin.Plugins.Stats
{ {
await Manager.AddMessageAsync(E.Origin.ClientId, await StatManager.GetIdForServer(E.Owner), E.Data); await Manager.AddMessageAsync(E.Origin.ClientId, await StatManager.GetIdForServer(E.Owner), E.Data);
} }
break; break;
case GameEvent.EventType.MapChange: case GameEvent.EventType.MapChange:
Manager.SetTeamBased(await StatManager.GetIdForServer(E.Owner), E.Owner.Gametype != "dm"); Manager.SetTeamBased(await StatManager.GetIdForServer(E.Owner), E.Owner.Gametype != "dm");
@ -79,6 +78,22 @@ namespace IW4MAdmin.Plugins.Stats
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 14) if (killInfo.Length >= 14)
{ {
if (E.Origin.ClientId <= 1 && E.Target.ClientId <= 1)
{
return;
}
// this treats "world" damage as self damage
if (E.Origin.ClientId <= 1)
{
E.Origin = E.Target;
}
if (E.Target.ClientId <= 1)
{
E.Target = E.Origin;
}
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8], await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]); killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
} }
@ -86,13 +101,18 @@ namespace IW4MAdmin.Plugins.Stats
case GameEvent.EventType.Kill: case GameEvent.EventType.Kill:
if (!E.Owner.CustomCallback) if (!E.Owner.CustomCallback)
{ {
if (E.Origin.ClientId <= 1 && E.Target.ClientId <= 1)
{
return;
}
// this treats "world" damage as self damage // this treats "world" damage as self damage
if (E.Origin.ClientId == 1) if (E.Origin.ClientId <= 1)
{ {
E.Origin = E.Target; E.Origin = E.Target;
} }
if (E.Target.ClientId == 1) if (E.Target.ClientId <= 1)
{ {
E.Target = E.Origin; E.Target = E.Origin;
} }
@ -103,13 +123,18 @@ namespace IW4MAdmin.Plugins.Stats
case GameEvent.EventType.Damage: case GameEvent.EventType.Damage:
if (!E.Owner.CustomCallback) if (!E.Owner.CustomCallback)
{ {
if (E.Origin.ClientId <= 1 && E.Target.ClientId <= 1)
{
return;
}
// this treats "world" damage as self damage // this treats "world" damage as self damage
if (E.Origin.ClientId == 1) if (E.Origin.ClientId <= 1)
{ {
E.Origin = E.Target; E.Origin = E.Target;
} }
if (E.Target.ClientId == 1) if (E.Target.ClientId <= 1)
{ {
E.Target = E.Origin; E.Target = E.Origin;
} }
@ -121,6 +146,22 @@ namespace IW4MAdmin.Plugins.Stats
killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 14) if (killInfo.Length >= 14)
{ {
if (E.Origin.ClientId <= 1 && E.Target.ClientId <= 1)
{
return;
}
// this treats "world" damage as self damage
if (E.Origin.ClientId <= 1)
{
E.Origin = E.Target;
}
if (E.Target.ClientId <= 1)
{
E.Target = E.Origin;
}
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8], await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]); killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
} }

View File

@ -18,7 +18,7 @@ namespace Tests
{ {
File.WriteAllText("test_mp.log", "test_log_file"); File.WriteAllText("test_mp.log", "test_log_file");
IW4MAdmin.Application.Localization.Configure.Initialize("en-US"); //IW4MAdmin.Application.Localization.Configure.Initialize("en-US");
Manager = ApplicationManager.GetInstance(); Manager = ApplicationManager.GetInstance();
@ -41,7 +41,7 @@ namespace Tests
Maps = new List<MapConfiguration>(), Maps = new List<MapConfiguration>(),
RConPollRate = 10000 RConPollRate = 10000
}; };
Manager.ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("test.json"); Manager.ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("test");
Manager.ConfigHandler.Set(config); Manager.ConfigHandler.Set(config);
Manager.Init().Wait(); Manager.Init().Wait();

View File

@ -34,7 +34,7 @@ namespace Tests
[Fact] [Fact]
public void AreCommandAliasesUnique() public void AreCommandAliasesUnique()
{ {
var mgr = IW4MAdmin.Application.Program.ServerManager; var mgr = Program.ServerManager;
bool test = mgr.GetCommands().Count == mgr.GetCommands().Select(c => c.Alias).Distinct().Count(); bool test = mgr.GetCommands().Count == mgr.GetCommands().Select(c => c.Alias).Distinct().Count();
Assert.True(test, "command aliases are not unique"); Assert.True(test, "command aliases are not unique");

View File

@ -28,7 +28,7 @@ namespace SharedLibraryCore.Configuration
public string WebfrontBindUrl { get; set; } public string WebfrontBindUrl { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_MANUAL_URL")] [LocalizedDisplayName("WEBFRONT_CONFIGURATION_MANUAL_URL")]
public string ManualWebfrontUrl { get; set; } public string ManualWebfrontUrl { get; set; }
public string WebfrontUrl => string.IsNullOrEmpty(ManualWebfrontUrl) ? WebfrontBindUrl.Replace("0.0.0.0", "127.0.0.1") : ManualWebfrontUrl; public string WebfrontUrl => string.IsNullOrEmpty(ManualWebfrontUrl) ? WebfrontBindUrl?.Replace("0.0.0.0", "127.0.0.1") : ManualWebfrontUrl;
[LocalizedDisplayName("SETUP_USE_CUSTOMENCODING")] [LocalizedDisplayName("SETUP_USE_CUSTOMENCODING")]
public bool EnableCustomParserEncoding { get; set; } public bool EnableCustomParserEncoding { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENCODING")] [LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENCODING")]

View File

@ -17,7 +17,6 @@ namespace SharedLibraryCore.Services
{ {
using (var context = new DatabaseContext()) using (var context = new DatabaseContext())
{ {
int? linkId = null; int? linkId = null;
int? aliasId = null; int? aliasId = null;
@ -45,23 +44,31 @@ namespace SharedLibraryCore.Services
NetworkId = entity.NetworkId NetworkId = entity.NetworkId
}; };
if (linkId.HasValue) // they're just using a new GUID
{
client.AliasLinkId = linkId.Value;
}
else
{
client.AliasLink = new EFAliasLink();
}
if (aliasId.HasValue) if (aliasId.HasValue)
{ {
client.CurrentAliasId = aliasId.Value; client.CurrentAliasId = aliasId.Value;
client.AliasLinkId = linkId.Value;
} }
// link was found but they don't have an exact alias
else if (!aliasId.HasValue && linkId.HasValue)
{
client.AliasLinkId = linkId.Value;
client.CurrentAlias = new Alias()
{
Name = entity.Name,
DateAdded = DateTime.UtcNow,
IPAddress = entity.IPAddress,
LinkId = linkId.Value
};
}
// brand new players (supposedly)
else else
{ {
client.AliasLink = new EFAliasLink();
client.CurrentAlias = new Alias() client.CurrentAlias = new Alias()
{ {
Name = entity.Name, Name = entity.Name,
@ -69,11 +76,6 @@ namespace SharedLibraryCore.Services
IPAddress = entity.IPAddress, IPAddress = entity.IPAddress,
Link = client.AliasLink, Link = client.AliasLink,
}; };
if (client.CurrentAlias.Link == null)
{
client.CurrentAlias.LinkId = linkId.Value;
}
} }
context.Clients.Add(client); context.Clients.Add(client);
@ -126,6 +128,11 @@ namespace SharedLibraryCore.Services
var oldAliasLink = entity.AliasLink; var oldAliasLink = entity.AliasLink;
// update all the clients that have the old alias link
await context.Clients
.Where(_client => _client.AliasLinkId == oldAliasLink.AliasLinkId)
.ForEachAsync(_client => _client.AliasLinkId = newAliasLink.AliasLinkId);
entity.AliasLink = newAliasLink; entity.AliasLink = newAliasLink;
entity.AliasLinkId = newAliasLink.AliasLinkId; entity.AliasLinkId = newAliasLink.AliasLinkId;

View File

@ -22,7 +22,8 @@ namespace SharedLibraryCore
public static class Utilities public static class Utilities
{ {
#if DEBUG == true #if DEBUG == true
public static string OperatingDirectory => $"{Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)}{Path.DirectorySeparatorChar}"; public static string OperatingDirectory => @"X:\IW4MAdmin\Application\bin\Debug\netcoreapp2.2\";
//public static string OperatingDirectory => $"{Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)}{Path.DirectorySeparatorChar}";
#else #else
public static string OperatingDirectory => $"{Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)}{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}"; public static string OperatingDirectory => $"{Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)}{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}";
#endif #endif