add game log server

This commit is contained in:
RaidMax 2018-09-06 13:25:58 -05:00
parent 0c90d02e44
commit 385879618d
23 changed files with 362 additions and 71 deletions

1
.gitignore vendored
View File

@ -228,3 +228,4 @@ bootstrap-custom.min.css
/DiscordWebhook/env
/DiscordWebhook/config.dev.json
/GameLogServer/env

View 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);
}
}

View 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; }
}
}

View File

@ -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
}
};
}

View File

@ -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;

View File

@ -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)
{

View File

@ -138,7 +138,7 @@ namespace IW4MAdmin.Application
};
ServerManager.GetEventHandler().AddEvent(E);
await E.OnProcessed.WaitAsync(30 * 1000);
await E.WaitAsync(30 * 1000);
}
Console.Write('>');

View File

@ -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()

View File

@ -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

View 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>

View File

@ -0,0 +1,9 @@
"""
The flask application package.
"""
from flask import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app)

View 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()

View 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
}

View 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>')

View 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

View 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)

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
}