fix issues with game interface reconnecting after rcon connection lost

This commit is contained in:
RaidMax 2022-08-26 12:07:43 -05:00
parent 527ffbaced
commit 7526f86dab
3 changed files with 81 additions and 17 deletions

View File

@ -42,6 +42,7 @@ namespace IW4MAdmin.Application.Misc
private Engine _scriptEngine; private Engine _scriptEngine;
private readonly string _fileName; private readonly string _fileName;
private readonly SemaphoreSlim _onProcessing = new(1, 1); private readonly SemaphoreSlim _onProcessing = new(1, 1);
private readonly SemaphoreSlim _onDvarActionComplete = new(1, 1);
private bool _successfullyLoaded; private bool _successfullyLoaded;
private readonly List<string> _registeredCommandNames; private readonly List<string> _registeredCommandNames;
private readonly ILogger _logger; private readonly ILogger _logger;
@ -458,18 +459,16 @@ namespace IW4MAdmin.Application.Misc
private void BeginGetDvar(Server server, string dvarName, Delegate onCompleted) private void BeginGetDvar(Server server, string dvarName, Delegate onCompleted)
{ {
var tokenSource = new CancellationTokenSource(); void OnComplete(IAsyncResult result)
tokenSource.CancelAfter(TimeSpan.FromSeconds(15));
server.BeginGetDvar(dvarName, result =>
{ {
var shouldRelease = false;
try try
{ {
_onProcessing.Wait(tokenSource.Token);
shouldRelease = true;
var (success, value) = (ValueTuple<bool, string>)result.AsyncState; var (success, value) = (ValueTuple<bool, string>)result.AsyncState;
_logger.LogDebug("Waiting for onDvarActionComplete -> get");
_onDvarActionComplete.Wait();
_logger.LogDebug("Completed wait for onDvarActionComplete -> get");
onCompleted.DynamicInvoke(JsValue.Undefined, onCompleted.DynamicInvoke(JsValue.Undefined,
new[] new[]
{ {
@ -479,9 +478,43 @@ namespace IW4MAdmin.Application.Misc
JsValue.FromObject(_scriptEngine, success) JsValue.FromObject(_scriptEngine, success)
}); });
} }
catch (JavaScriptException ex)
{
using (LogContext.PushProperty("Server", server.ToString()))
{
_logger.LogError(ex, "Could complete BeginGetDvar for {Filename} {@Location}",
Path.GetFileName(_fileName), ex.Location);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Could not complete {BeginGetDvar} for {Class}", nameof(BeginGetDvar), Name);
}
finally
{
if (_onDvarActionComplete.CurrentCount == 0)
{
_onDvarActionComplete.Release();
}
}
}
var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(15));
server.BeginGetDvar(dvarName, result =>
{
var shouldRelease = false;
try
{
_onProcessing.Wait(tokenSource.Token);
shouldRelease = true;
}
finally finally
{ {
OnComplete(result);
if (_onProcessing.CurrentCount == 0 && shouldRelease) if (_onProcessing.CurrentCount == 0 && shouldRelease)
{ {
_onProcessing.Release(); _onProcessing.Release();
@ -495,15 +528,15 @@ namespace IW4MAdmin.Application.Misc
var tokenSource = new CancellationTokenSource(); var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(15)); tokenSource.CancelAfter(TimeSpan.FromSeconds(15));
server.BeginSetDvar(dvarName, dvarValue, result => void OnComplete(IAsyncResult result)
{ {
var shouldRelease = false;
try try
{ {
_onProcessing.Wait(tokenSource.Token);
shouldRelease = true;
var success = (bool)result.AsyncState; var success = (bool)result.AsyncState;
_logger.LogDebug("Waiting for onDvarActionComplete -> set");
_onDvarActionComplete.Wait();
_logger.LogDebug("Completed wait for onDvarActionComplete -> set");
onCompleted.DynamicInvoke(JsValue.Undefined, onCompleted.DynamicInvoke(JsValue.Undefined,
new[] new[]
{ {
@ -513,8 +546,38 @@ namespace IW4MAdmin.Application.Misc
JsValue.FromObject(_scriptEngine, success) JsValue.FromObject(_scriptEngine, success)
}); });
} }
catch (JavaScriptException ex)
{
using (LogContext.PushProperty("Server", server.ToString()))
{
_logger.LogError(ex, "Could complete BeginSetDvar for {Filename} {@Location}",
Path.GetFileName(_fileName), ex.Location);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Could not complete {BeginSetDvar} for {Class}", nameof(BeginSetDvar), Name);
}
finally finally
{ {
if (_onDvarActionComplete.CurrentCount == 0)
{
_onDvarActionComplete.Release();
}
}
}
server.BeginSetDvar(dvarName, dvarValue, result =>
{
var shouldRelease = false;
try
{
_onProcessing.Wait(tokenSource.Token);
shouldRelease = true;
}
finally
{
OnComplete(result);
if (_onProcessing.CurrentCount == 0 && shouldRelease) if (_onProcessing.CurrentCount == 0 && shouldRelease)
{ {
_onProcessing.Release(); _onProcessing.Release();

View File

@ -111,7 +111,7 @@ public class ScriptPluginTimerHelper : IScriptPluginTimerHelper
{ {
return; return;
} }
_logger.LogDebug("-Releasing OnTick for timer");
_onDependentAction?.Release(1); _onDependentAction?.Release(1);
} }
private void OnTick() private void OnTick()
@ -128,7 +128,8 @@ public class ScriptPluginTimerHelper : IScriptPluginTimerHelper
_onRunningTick.Reset(); _onRunningTick.Reset();
// the js engine is not thread safe so we need to ensure we're not executing OnTick and OnEventAsync simultaneously // the js engine is not thread safe so we need to ensure we're not executing OnTick and OnEventAsync simultaneously
_onDependentAction?.WaitAsync().Wait(); _onDependentAction?.Wait();
_logger.LogDebug("+Running OnTick for timer");
var start = DateTime.Now; var start = DateTime.Now;
_jsAction.DynamicInvoke(JsValue.Undefined, new[] { JsValue.Undefined }); _jsAction.DynamicInvoke(JsValue.Undefined, new[] { JsValue.Undefined });
_logger.LogDebug("OnTick took {Time}ms", (DateTime.Now - start).TotalMilliseconds); _logger.LogDebug("OnTick took {Time}ms", (DateTime.Now - start).TotalMilliseconds);

View File

@ -147,7 +147,7 @@ namespace IW4MAdmin.Application.RConParsers
{ {
GetDvarAsync<string>(connection, dvarName, token: token).ContinueWith(action => GetDvarAsync<string>(connection, dvarName, token: token).ContinueWith(action =>
{ {
if (action.Exception is null) if (action.Exception is null && !action.IsCanceled)
{ {
callback?.Invoke(new AsyncResult callback?.Invoke(new AsyncResult
{ {
@ -164,7 +164,7 @@ namespace IW4MAdmin.Application.RConParsers
AsyncState = (false, (string)null) AsyncState = (false, (string)null)
}); });
} }
}, token); }, CancellationToken.None);
} }
public virtual async Task<IStatusResponse> GetStatusAsync(IRConConnection connection, CancellationToken token = default) public virtual async Task<IStatusResponse> GetStatusAsync(IRConConnection connection, CancellationToken token = default)
@ -227,7 +227,7 @@ namespace IW4MAdmin.Application.RConParsers
{ {
SetDvarAsync(connection, dvarName, dvarValue, token).ContinueWith(action => SetDvarAsync(connection, dvarName, dvarValue, token).ContinueWith(action =>
{ {
if (action.Exception is null) if (action.Exception is null && !action.IsCanceled)
{ {
callback?.Invoke(new AsyncResult callback?.Invoke(new AsyncResult
{ {
@ -244,7 +244,7 @@ namespace IW4MAdmin.Application.RConParsers
AsyncState = false AsyncState = false
}); });
} }
}, token); }, CancellationToken.None);
} }
private List<EFClient> ClientsFromStatus(string[] Status) private List<EFClient> ClientsFromStatus(string[] Status)