add game log server
This commit is contained in:
parent
0c90d02e44
commit
385879618d
1
.gitignore
vendored
1
.gitignore
vendored
@ -228,3 +228,4 @@ bootstrap-custom.min.css
|
||||
|
||||
/DiscordWebhook/env
|
||||
/DiscordWebhook/config.dev.json
|
||||
/GameLogServer/env
|
||||
|
12
Application/API/GameLogServer/IGameLogServer.cs
Normal file
12
Application/API/GameLogServer/IGameLogServer.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Threading.Tasks;
|
||||
using RestEase;
|
||||
|
||||
namespace IW4MAdmin.Application.API.GameLogServer
|
||||
{
|
||||
[Header("User-Agent", "IW4MAdmin-RestEase")]
|
||||
public interface IGameLogServer
|
||||
{
|
||||
[Get("log/{path}")]
|
||||
Task<LogInfo> Log([Path] string path);
|
||||
}
|
||||
}
|
17
Application/API/GameLogServer/LogInfo.cs
Normal file
17
Application/API/GameLogServer/LogInfo.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace IW4MAdmin.Application.API.GameLogServer
|
||||
{
|
||||
public class LogInfo
|
||||
{
|
||||
[JsonProperty("success")]
|
||||
public bool Success { get; set; }
|
||||
[JsonProperty("length")]
|
||||
public int Length { get; set; }
|
||||
[JsonProperty("data")]
|
||||
public string Data { get; set; }
|
||||
}
|
||||
}
|
@ -84,7 +84,6 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (eventType == "ScriptKill")
|
||||
{
|
||||
var origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
|
||||
@ -152,7 +151,8 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
Name = regexMatch.Groups[4].ToString().StripColors(),
|
||||
NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
|
||||
ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()),
|
||||
State = Player.ClientState.Connecting
|
||||
State = Player.ClientState.Connecting,
|
||||
CurrentServer = server
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -68,7 +68,8 @@ namespace IW4MAdmin.Application.IO
|
||||
|
||||
long fileDiff = fileSize - PreviousFileSize;
|
||||
|
||||
if (fileDiff < 1)
|
||||
// this makes the http log get pulled
|
||||
if (fileDiff < 1 && fileSize != -1)
|
||||
return;
|
||||
|
||||
PreviousFileSize = fileSize;
|
||||
|
@ -1,8 +1,11 @@
|
||||
using SharedLibraryCore;
|
||||
using IW4MAdmin.Application.API.GameLogServer;
|
||||
using RestEase;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using static SharedLibraryCore.Utilities;
|
||||
|
||||
namespace IW4MAdmin.Application.IO
|
||||
{
|
||||
@ -12,31 +15,17 @@ namespace IW4MAdmin.Application.IO
|
||||
class GameLogReaderHttp : IGameLogReader
|
||||
{
|
||||
readonly IEventParser Parser;
|
||||
readonly IGameLogServer Api;
|
||||
readonly string LogFile;
|
||||
|
||||
public GameLogReaderHttp(string logFile, IEventParser parser)
|
||||
{
|
||||
LogFile = logFile;
|
||||
Parser = parser;
|
||||
Api = RestClient.For<IGameLogServer>(logFile);
|
||||
}
|
||||
|
||||
public long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
using (var cl = new HttpClient())
|
||||
{
|
||||
using (var re = cl.GetAsync($"{LogFile}&length=1").Result)
|
||||
{
|
||||
using (var content = re.Content)
|
||||
{
|
||||
string response = content.ReadAsStringAsync().Result ?? "0";
|
||||
return Convert.ToInt64(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public long Length => -1;
|
||||
|
||||
public int UpdateInterval => 1000;
|
||||
|
||||
@ -45,29 +34,17 @@ namespace IW4MAdmin.Application.IO
|
||||
#if DEBUG == true
|
||||
server.Logger.WriteDebug($"Begin reading {fileSizeDiff} from http log");
|
||||
#endif
|
||||
string log;
|
||||
using (var cl = new HttpClient())
|
||||
{
|
||||
using (var re = cl.GetAsync($"{LogFile}&start={fileSizeDiff}").Result)
|
||||
{
|
||||
using (var content = re.Content)
|
||||
{
|
||||
log = content.ReadAsStringAsync().Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if DEBUG == true
|
||||
server.Logger.WriteDebug($"retrieved events from http log");
|
||||
#endif
|
||||
List<GameEvent> events = new List<GameEvent>();
|
||||
string[] lines = log.Split(Environment.NewLine);
|
||||
var events = new List<GameEvent>();
|
||||
string b64Path = server.LogPath.ToBase64UrlSafeString();
|
||||
var response = Api.Log(b64Path).Result;
|
||||
|
||||
#if DEBUG == true
|
||||
server.Logger.WriteDebug($"Begin parse of {lines.Length} lines from http log");
|
||||
#endif
|
||||
if (!response.Success)
|
||||
{
|
||||
server.Logger.WriteError($"Could not get log server info of {LogFile}/{b64Path} ({server.LogPath})");
|
||||
}
|
||||
|
||||
// parse each line
|
||||
foreach (string eventLine in lines)
|
||||
foreach (string eventLine in response.Data.Split(Environment.NewLine))
|
||||
{
|
||||
if (eventLine.Length > 0)
|
||||
{
|
||||
|
@ -138,7 +138,7 @@ namespace IW4MAdmin.Application
|
||||
};
|
||||
|
||||
ServerManager.GetEventHandler().AddEvent(E);
|
||||
await E.OnProcessed.WaitAsync(30 * 1000);
|
||||
await E.WaitAsync(30 * 1000);
|
||||
}
|
||||
Console.Write('>');
|
||||
|
||||
|
@ -100,9 +100,7 @@ namespace IW4MAdmin.Application
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//// todo: this is a hacky mess
|
||||
// todo: this is a hacky mess
|
||||
if (newEvent.Origin?.DelayedEvents.Count > 0 &&
|
||||
newEvent.Origin?.State == Player.ClientState.Connected)
|
||||
{
|
||||
@ -175,7 +173,7 @@ namespace IW4MAdmin.Application
|
||||
Logger.WriteDebug("Error Trace: " + ex.StackTrace);
|
||||
}
|
||||
// tell anyone waiting for the output that we're done
|
||||
newEvent.OnProcessed.Release();
|
||||
newEvent.OnProcessed.Set();
|
||||
}
|
||||
|
||||
public IList<Server> GetServers()
|
||||
|
@ -567,7 +567,7 @@ namespace IW4MAdmin
|
||||
try
|
||||
{
|
||||
var polledClients = await PollPlayersAsync();
|
||||
var waiterList = new List<SemaphoreSlim>();
|
||||
var waiterList = new List<GameEvent>();
|
||||
|
||||
foreach (var disconnectingClient in polledClients[1])
|
||||
{
|
||||
@ -586,10 +586,10 @@ namespace IW4MAdmin
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
// wait until the disconnect event is complete
|
||||
// because we don't want to try to fill up a slot that's not empty yet
|
||||
waiterList.Add(e.OnProcessed);
|
||||
waiterList.Add(e);
|
||||
}
|
||||
// wait for all the disconnect tasks to finish
|
||||
await Task.WhenAll(waiterList.Select(t => t.WaitAsync()));
|
||||
await Task.WhenAll(waiterList.Select(e => e.WaitAsync()));
|
||||
|
||||
waiterList.Clear();
|
||||
// this are our new connecting clients
|
||||
@ -610,11 +610,11 @@ namespace IW4MAdmin
|
||||
};
|
||||
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
waiterList.Add(e.OnProcessed);
|
||||
waiterList.Add(e);
|
||||
}
|
||||
|
||||
// wait for all the connect tasks to finish
|
||||
await Task.WhenAll(waiterList.Select(t => t.WaitAsync()));
|
||||
await Task.WhenAll(waiterList.Select(e => e.WaitAsync()));
|
||||
|
||||
if (ConnectionErrors > 0)
|
||||
{
|
||||
@ -788,25 +788,28 @@ namespace IW4MAdmin
|
||||
#if DEBUG
|
||||
basepath.Value = @"D:\";
|
||||
#endif
|
||||
string logPath;
|
||||
string logPath = string.Empty;
|
||||
|
||||
LogPath = game == string.Empty ?
|
||||
$"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile.Value}" :
|
||||
$"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile.Value}";
|
||||
|
||||
if (GameName == Game.IW5 || ServerConfig.ManualLogPath?.Length > 0)
|
||||
{
|
||||
logPath = ServerConfig.ManualLogPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
logPath = game == string.Empty ?
|
||||
$"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile.Value}" :
|
||||
$"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile.Value}";
|
||||
logPath = LogPath;
|
||||
}
|
||||
|
||||
// hopefully fix wine drive name mangling
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
logPath = Regex.Replace($"{Path.DirectorySeparatorChar}{logPath}", @"[A-Z]:", "");
|
||||
logPath = Regex.Replace($"{Path.DirectorySeparatorChar}{LogPath}", @"[A-Z]:", "");
|
||||
}
|
||||
|
||||
if (!File.Exists(logPath) && !logPath.StartsWith("http"))
|
||||
if (!File.Exists(LogPath) && !logPath.StartsWith("http"))
|
||||
{
|
||||
Logger.WriteError($"{logPath} {loc["SERVER_ERROR_DNE"]}");
|
||||
#if !DEBUG
|
||||
|
99
GameLogServer/GameLogServer.pyproj
Normal file
99
GameLogServer/GameLogServer.pyproj
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>42efda12-10d3-4c40-a210-9483520116bc</ProjectGuid>
|
||||
<ProjectHome>.</ProjectHome>
|
||||
<ProjectTypeGuids>{789894c7-04a9-4a11-a6b5-3f4435165112};{1b580a1a-fdb3-4b32-83e1-6407eb2722e6};{349c5851-65df-11da-9384-00065b846f21};{888888a0-9f3d-457c-b088-3a5042f75d52}</ProjectTypeGuids>
|
||||
<StartupFile>runserver.py</StartupFile>
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<LaunchProvider>Web launcher</LaunchProvider>
|
||||
<WebBrowserUrl>http://localhost</WebBrowserUrl>
|
||||
<OutputPath>.</OutputPath>
|
||||
<SuppressCollectPythonCloudServiceFiles>true</SuppressCollectPythonCloudServiceFiles>
|
||||
<Name>GameLogServer</Name>
|
||||
<RootNamespace>GameLogServer</RootNamespace>
|
||||
<InterpreterId>MSBuild|env|$(MSBuildProjectFullPath)</InterpreterId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="GameLogServer\log_reader.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GameLogServer\server.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="runserver.py" />
|
||||
<Compile Include="GameLogServer\__init__.py" />
|
||||
<Compile Include="GameLogServer\log_resource.py" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="GameLogServer\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="FolderProfile.pubxml" />
|
||||
<Content Include="requirements.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Interpreter Include="env\">
|
||||
<Id>env</Id>
|
||||
<Version>3.6</Version>
|
||||
<Description>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>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.Web.targets" />
|
||||
<!-- Specify pre- and post-build commands in the BeforeBuild and
|
||||
AfterBuild targets below. -->
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://localhost</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}" User="">
|
||||
<WebProjectProperties>
|
||||
<StartPageUrl>
|
||||
</StartPageUrl>
|
||||
<StartAction>CurrentPage</StartAction>
|
||||
<AspNetDebugging>True</AspNetDebugging>
|
||||
<SilverlightDebugging>False</SilverlightDebugging>
|
||||
<NativeDebugging>False</NativeDebugging>
|
||||
<SQLDebugging>False</SQLDebugging>
|
||||
<ExternalProgram>
|
||||
</ExternalProgram>
|
||||
<StartExternalURL>
|
||||
</StartExternalURL>
|
||||
<StartCmdLineArguments>
|
||||
</StartCmdLineArguments>
|
||||
<StartWorkingDirectory>
|
||||
</StartWorkingDirectory>
|
||||
<EnableENC>False</EnableENC>
|
||||
<AlwaysStartWebServerOnDebug>False</AlwaysStartWebServerOnDebug>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
9
GameLogServer/GameLogServer/__init__.py
Normal file
9
GameLogServer/GameLogServer/__init__.py
Normal file
@ -0,0 +1,9 @@
|
||||
"""
|
||||
The flask application package.
|
||||
"""
|
||||
|
||||
from flask import Flask
|
||||
from flask_restful import Api
|
||||
|
||||
app = Flask(__name__)
|
||||
api = Api(app)
|
75
GameLogServer/GameLogServer/log_reader.py
Normal file
75
GameLogServer/GameLogServer/log_reader.py
Normal file
@ -0,0 +1,75 @@
|
||||
import re
|
||||
import os
|
||||
import time
|
||||
|
||||
class LogReader(object):
|
||||
def __init__(self):
|
||||
self.log_file_sizes = {}
|
||||
# (if the file changes more than this, ignore ) - 1 MB
|
||||
self.max_file_size_change = 1000000
|
||||
# (if the time between checks is greater, ignore ) - 5 minutes
|
||||
self.max_file_time_change = 300
|
||||
|
||||
def read_file(self, path):
|
||||
# prevent traversing directories
|
||||
if re.search('r^.+\.\.\\.+$', path):
|
||||
return False
|
||||
# must be a valid log path and log file
|
||||
if not re.search(r'^.+[\\|\/](userraw|mods)[\\|\/].+.log$', path):
|
||||
return False
|
||||
# set the initialze size to the current file size
|
||||
file_size = 0
|
||||
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']
|
||||
last_read = self.log_file_sizes[path]['read']
|
||||
|
||||
# the file is being tracked already
|
||||
new_file_size = self.file_length(path)
|
||||
|
||||
# the log size was unable to be read (probably the wrong path)
|
||||
if new_file_size < 0:
|
||||
return False
|
||||
|
||||
now = time.time()
|
||||
|
||||
file_size_difference = new_file_size - last_length
|
||||
time_difference = now - last_read
|
||||
|
||||
# update the new size and actually read the data
|
||||
self.log_file_sizes[path] = {
|
||||
'length': new_file_size,
|
||||
'read': now
|
||||
}
|
||||
|
||||
# if it's been too long since we read and the amount changed is too great, discard it
|
||||
# todo: do we really want old events? maybe make this an "or"
|
||||
if file_size_difference > self.max_file_size_change and time_difference > self.max_file_time_change:
|
||||
return ''
|
||||
|
||||
new_log_info = self.get_file_lines(path, file_size_difference)
|
||||
return new_log_info
|
||||
|
||||
def get_file_lines(self, path, length):
|
||||
try:
|
||||
file_handle = open(path, 'rb')
|
||||
file_handle.seek(-length, 2)
|
||||
file_data = file_handle.read(length)
|
||||
file_handle.close()
|
||||
return file_data.decode('utf-8')
|
||||
except:
|
||||
return False
|
||||
|
||||
def file_length(self, path):
|
||||
try:
|
||||
return os.stat(path).st_size
|
||||
except:
|
||||
return -1
|
||||
|
||||
reader = LogReader()
|
17
GameLogServer/GameLogServer/log_resource.py
Normal file
17
GameLogServer/GameLogServer/log_resource.py
Normal file
@ -0,0 +1,17 @@
|
||||
from flask_restful import Resource
|
||||
from GameLogServer.log_reader import reader
|
||||
from base64 import urlsafe_b64decode
|
||||
|
||||
class LogResource(Resource):
|
||||
def get(self, path):
|
||||
path = urlsafe_b64decode(path).decode('utf-8')
|
||||
log_info = reader.read_file(path)
|
||||
|
||||
if not log_info:
|
||||
print('could not read log file ' + path)
|
||||
|
||||
return {
|
||||
'success' : log_info is not False,
|
||||
'length': -1 if log_info is False else len(log_info),
|
||||
'data': log_info
|
||||
}
|
9
GameLogServer/GameLogServer/server.py
Normal file
9
GameLogServer/GameLogServer/server.py
Normal file
@ -0,0 +1,9 @@
|
||||
from flask import Flask
|
||||
from flask_restful import Api
|
||||
from .log_resource import LogResource
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def init():
|
||||
api = Api(app)
|
||||
api.add_resource(LogResource, '/log/<string:path>')
|
12
GameLogServer/requirements.txt
Normal file
12
GameLogServer/requirements.txt
Normal file
@ -0,0 +1,12 @@
|
||||
Flask==1.0.2
|
||||
aniso8601==3.0.2
|
||||
click==6.7
|
||||
Flask-RESTful==0.3.6
|
||||
itsdangerous==0.24
|
||||
Jinja2==2.10
|
||||
MarkupSafe==1.0
|
||||
pip==9.0.3
|
||||
pytz==2018.5
|
||||
setuptools==39.0.1
|
||||
six==1.11.0
|
||||
Werkzeug==0.14.1
|
15
GameLogServer/runserver.py
Normal file
15
GameLogServer/runserver.py
Normal file
@ -0,0 +1,15 @@
|
||||
"""
|
||||
This script runs the GameLogServer application using a development server.
|
||||
"""
|
||||
|
||||
from os import environ
|
||||
from GameLogServer.server import app, init
|
||||
|
||||
if __name__ == '__main__':
|
||||
HOST = environ.get('SERVER_HOST', '0.0.0.0')
|
||||
try:
|
||||
PORT = int(environ.get('SERVER_PORT', '1625'))
|
||||
except ValueError:
|
||||
PORT = 5555
|
||||
init()
|
||||
app.run(HOST, PORT, debug=True)
|
@ -31,7 +31,7 @@ Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "Master", "Master\Master.pyp
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Plugins\Tests\Tests.csproj", "{B72DEBFB-9D48-4076-8FF5-1FD72A830845}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IW4ScriptCommands", "Plugins\IW4ScriptCommands\IW4ScriptCommands.csproj", "{6C706CE5-A206-4E46-8712-F8C48D526091}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IW4ScriptCommands", "Plugins\IW4ScriptCommands\IW4ScriptCommands.csproj", "{6C706CE5-A206-4E46-8712-F8C48D526091}"
|
||||
EndProject
|
||||
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "DiscordWebhook", "DiscordWebhook\DiscordWebhook.pyproj", "{15A81D6E-7502-46CE-8530-0647A380B5F4}"
|
||||
EndProject
|
||||
@ -40,6 +40,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ScriptPlugins", "ScriptPlug
|
||||
Plugins\ScriptPlugins\VPNDetection.js = Plugins\ScriptPlugins\VPNDetection.js
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "GameLogServer", "GameLogServer\GameLogServer.pyproj", "{42EFDA12-10D3-4C40-A210-9483520116BC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -306,6 +308,30 @@ Global
|
||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|x64.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|x64.Build.0 = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|x86.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|x86.Build.0 = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1,9 +1,6 @@
|
||||
using IW4MAdmin.Application;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace Tests
|
||||
@ -43,7 +40,7 @@ namespace Tests
|
||||
Type = GameEvent.EventType.Say,
|
||||
Origin = client,
|
||||
Data = "nigger",
|
||||
Owner = client.CurrentServer
|
||||
Owner = e.Owner
|
||||
};
|
||||
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharedLibraryCore.Objects;
|
||||
|
||||
namespace SharedLibraryCore
|
||||
@ -50,8 +51,7 @@ namespace SharedLibraryCore
|
||||
|
||||
public GameEvent()
|
||||
{
|
||||
OnProcessed = new SemaphoreSlim(0);
|
||||
OnProcessed.Release();
|
||||
OnProcessed = new ManualResetEventSlim();
|
||||
Time = DateTime.UtcNow;
|
||||
Id = GetNextEventId();
|
||||
}
|
||||
@ -64,10 +64,16 @@ namespace SharedLibraryCore
|
||||
public Server Owner;
|
||||
public Boolean Remote = false;
|
||||
public object Extra { get; set; }
|
||||
public SemaphoreSlim OnProcessed { get; set; }
|
||||
public ManualResetEventSlim OnProcessed { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
public long Id { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// asynchronously wait for GameEvent to be processed
|
||||
/// </summary>
|
||||
/// <returns>waitable task </returns>
|
||||
public Task<bool> WaitAsync(int timeOut = int.MaxValue) => Task.FromResult(OnProcessed.Wait(timeOut));
|
||||
|
||||
/// <summary>
|
||||
/// determine whether an event should be delayed or not
|
||||
/// applies only to the origin entity
|
||||
|
@ -12,7 +12,7 @@ namespace SharedLibraryCore.Configuration
|
||||
{
|
||||
public class BaseConfigurationHandler<T> : IConfigurationHandler<T> where T : IBaseConfiguration
|
||||
{
|
||||
string Filename;
|
||||
readonly string Filename;
|
||||
IConfigurationRoot ConfigurationRoot { get; set; }
|
||||
T _configuration;
|
||||
|
||||
|
@ -310,6 +310,7 @@ namespace SharedLibraryCore
|
||||
public RCon.Connection RemoteConnection { get; protected set; }
|
||||
public IRConParser RconParser { get; protected set; }
|
||||
public IEventParser EventParser { get; set; }
|
||||
public string LogPath { get; protected set; }
|
||||
|
||||
// Internal
|
||||
protected string IP;
|
||||
|
@ -479,6 +479,7 @@ 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 Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName) => server.RconParser.GetDvarAsync<T>(server.RemoteConnection, dvarName);
|
||||
|
||||
|
@ -47,13 +47,28 @@ namespace WebfrontCore.Controllers
|
||||
};
|
||||
|
||||
Manager.GetEventHandler().AddEvent(remoteEvent);
|
||||
List<CommandResponseInfo> response;
|
||||
// wait for the event to process
|
||||
await remoteEvent.OnProcessed.WaitAsync(60*1000);
|
||||
var response = server.CommandResult.Where(c => c.ClientId == client.ClientId).ToList();
|
||||
if (await remoteEvent.WaitAsync(60 * 1000))
|
||||
{
|
||||
response = server.CommandResult.Where(c => c.ClientId == client.ClientId).ToList();
|
||||
|
||||
// remove the added command response
|
||||
for (int i = 0; i < response.Count; i++)
|
||||
server.CommandResult.Remove(response[i]);
|
||||
// remove the added command response
|
||||
for (int i = 0; i < response.Count; i++)
|
||||
server.CommandResult.Remove(response[i]);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
response = new List<CommandResponseInfo>()
|
||||
{
|
||||
new CommandResponseInfo()
|
||||
{
|
||||
ClientId = client.ClientId,
|
||||
Response = Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMAND_TIMEOUT"]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return View("_Response", response);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user