From 9d9be7f8af9d71eaa9d6e32c8442d147bfc88535 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Mon, 8 Apr 2019 12:29:48 -0500 Subject: [PATCH] few more small fixes complete join button on webfront update for 2.2.6.0 --- Application/API/Master/Heartbeat.cs | 2 + Application/ApplicationManager.cs | 34 ++++++++----- Application/IW4MServer.cs | 18 +++++-- SharedLibraryCore/Database/Models/EFClient.cs | 4 +- SharedLibraryCore/Dtos/ServerInfo.cs | 1 + SharedLibraryCore/Interfaces/IManager.cs | 1 + SharedLibraryCore/Objects/EFClient.cs | 12 ++++- SharedLibraryCore/Services/ClientService.cs | 2 +- SharedLibraryCore/Utilities.cs | 48 +++++++++++++++++++ .../ViewComponents/ServerListViewComponent.cs | 5 +- WebfrontCore/Views/Server/_Server.cshtml | 3 +- WebfrontCore/wwwroot/js/server.js | 6 +++ 12 files changed, 113 insertions(+), 23 deletions(-) diff --git a/Application/API/Master/Heartbeat.cs b/Application/API/Master/Heartbeat.cs index 0776ba75a..7fbb1843c 100644 --- a/Application/API/Master/Heartbeat.cs +++ b/Application/API/Master/Heartbeat.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using RestEase; using SharedLibraryCore; @@ -11,6 +12,7 @@ namespace IW4MAdmin.Application.API.Master public class HeartbeatState { public bool Connected { get; set; } + public CancellationToken Token { get; set; } } public class Heartbeat diff --git a/Application/ApplicationManager.cs b/Application/ApplicationManager.cs index a9c27d058..fbdc44b8a 100644 --- a/Application/ApplicationManager.cs +++ b/Application/ApplicationManager.cs @@ -41,10 +41,9 @@ namespace IW4MAdmin.Application public IList AdditionalRConParsers { get; } public IList AdditionalEventParsers { get; } - public ITokenAuthentication TokenAuthenticator => Authenticator; - public ITokenAuthentication Authenticator => _authenticator; + public string ExternalIPAddress { get; private set; } static ApplicationManager Instance; readonly List TaskStatuses; @@ -158,7 +157,7 @@ namespace IW4MAdmin.Application return Instance ?? (Instance = new ApplicationManager()); } - public async Task UpdateServerStates() + public async Task UpdateServerStates(CancellationToken token) { // store the server hash code and task for it var runningUpdateTasks = new Dictionary(); @@ -215,17 +214,19 @@ namespace IW4MAdmin.Application ThreadPool.GetAvailableThreads(out int availableThreads, out int m); Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks"); #endif - await Task.Delay(ConfigHandler.Configuration().RConPollRate); + try + { + await Task.Delay(ConfigHandler.Configuration().RConPollRate, token); + } + // if a cancellation is received, we want to return immediately + catch { break; } } - - // trigger the event processing loop to end - SetHasEvent(); } public async Task Init() { Running = true; - + ExternalIPAddress = await Utilities.GetExternalIP(); #region PLUGINS SharedLibraryCore.Plugins.PluginImporter.Load(this); @@ -642,27 +643,34 @@ namespace IW4MAdmin.Application } } - await Task.Delay(30000); + + try + { + await Task.Delay(30000, heartbeatState.Token); + } + catch { break; } } } public void Start() { + var tokenSource = new CancellationTokenSource(); // this needs to be run seperately from the main thread - var _ = Task.Run(() => SendHeartbeat(new HeartbeatState())); - _ = Task.Run(() => UpdateServerStates()); + _ = Task.Run(() => SendHeartbeat(new HeartbeatState() { Token = tokenSource.Token })); + _ = Task.Run(() => UpdateServerStates(tokenSource.Token)); while (Running) { OnQuit.Wait(); + tokenSource.Cancel(); OnQuit.Reset(); } - _servers.Clear(); } public void Stop() { Running = false; + OnQuit.Set(); } public ILogger GetLogger(long serverId) @@ -737,7 +745,7 @@ namespace IW4MAdmin.Application public void SetHasEvent() { - OnQuit.Set(); + } public IList GetPluginAssemblies() diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs index ef18ef1d7..a6a452a0a 100644 --- a/Application/IW4MServer.cs +++ b/Application/IW4MServer.cs @@ -176,7 +176,7 @@ namespace IW4MAdmin { if (E.Type == GameEvent.EventType.ChangePermission) { - var newPermission = (EFClient.Permission)E.Extra; + var newPermission = (Permission)E.Extra; if (newPermission < Permission.Moderator) { @@ -189,7 +189,8 @@ namespace IW4MAdmin Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target; } - await Manager.GetClientService().UpdateLevel((Permission)E.Extra, E.Target, E.Origin); + Logger.WriteInfo($"{E.Origin} is setting {E.Target} to permission level {newPermission}"); + await Manager.GetClientService().UpdateLevel(newPermission, E.Target, E.Origin); } else if (E.Type == GameEvent.EventType.PreConnect) @@ -342,7 +343,7 @@ namespace IW4MAdmin #endif } - else + else if (client?.State != ClientState.Disconnecting) { Logger.WriteWarning($"Client {E.Origin} detected as disconnecting, but could not find them in the player list"); Logger.WriteDebug($"Expected {E.Origin} but found {GetClientsAsList().FirstOrDefault(_client => _client.ClientNumber == E.Origin.ClientNumber)}"); @@ -471,7 +472,16 @@ namespace IW4MAdmin !client.IsBot && client.State == ClientState.Connected) { - await client.OnJoin(origin.IPAddress); + try + { + await client.OnJoin(origin.IPAddress); + } + + catch (Exception e) + { + origin.CurrentServer.Logger.WriteWarning($"Could not execute on join for {origin}"); + origin.CurrentServer.Logger.WriteDebug(e.GetExceptionInfo()); + } } } } diff --git a/SharedLibraryCore/Database/Models/EFClient.cs b/SharedLibraryCore/Database/Models/EFClient.cs index b0b34e792..2b8e9baa1 100644 --- a/SharedLibraryCore/Database/Models/EFClient.cs +++ b/SharedLibraryCore/Database/Models/EFClient.cs @@ -40,8 +40,8 @@ namespace SharedLibraryCore.Database.Models [NotMapped] public virtual string Name { - get { return CurrentAlias.Name; } - set { CurrentAlias.Name = value; } + get { return CurrentAlias?.Name ?? "--"; } + set { if (CurrentAlias != null) CurrentAlias.Name = value; } } [NotMapped] public virtual int? IPAddress diff --git a/SharedLibraryCore/Dtos/ServerInfo.cs b/SharedLibraryCore/Dtos/ServerInfo.cs index 29b430c5e..b86369f26 100644 --- a/SharedLibraryCore/Dtos/ServerInfo.cs +++ b/SharedLibraryCore/Dtos/ServerInfo.cs @@ -20,5 +20,6 @@ namespace SharedLibraryCore.Dtos public long ID { get; set; } public bool Online { get; set; } public string ConnectProtocolUrl { get; set; } + public string IPAddress { get; set; } } } diff --git a/SharedLibraryCore/Interfaces/IManager.cs b/SharedLibraryCore/Interfaces/IManager.cs index 8c0e79dee..e471f5813 100644 --- a/SharedLibraryCore/Interfaces/IManager.cs +++ b/SharedLibraryCore/Interfaces/IManager.cs @@ -46,5 +46,6 @@ namespace SharedLibraryCore.Interfaces IEventParser GenerateDynamicEventParser(); string Version { get;} ITokenAuthentication TokenAuthenticator { get; } + string ExternalIPAddress { get; } } } diff --git a/SharedLibraryCore/Objects/EFClient.cs b/SharedLibraryCore/Objects/EFClient.cs index e737f5c20..177fc34f6 100644 --- a/SharedLibraryCore/Objects/EFClient.cs +++ b/SharedLibraryCore/Objects/EFClient.cs @@ -467,7 +467,17 @@ namespace SharedLibraryCore.Database.Models State = ClientState.Disconnecting; TotalConnectionTime += ConnectionLength; LastConnection = DateTime.UtcNow; - await CurrentServer.Manager.GetClientService().Update(this); + + try + { + await CurrentServer.Manager.GetClientService().Update(this); + } + + catch (Exception e) + { + CurrentServer.Logger.WriteWarning($"Could not update disconnected player {this}"); + CurrentServer.Logger.WriteDebug(e.GetExceptionInfo()); + } } public async Task OnJoin(int? ipAddress) diff --git a/SharedLibraryCore/Services/ClientService.cs b/SharedLibraryCore/Services/ClientService.cs index e91ef6dbc..cbc37178b 100644 --- a/SharedLibraryCore/Services/ClientService.cs +++ b/SharedLibraryCore/Services/ClientService.cs @@ -248,6 +248,7 @@ namespace SharedLibraryCore.Services Type = GameEvent.EventType.ChangePermission, Extra = newPermission, Origin = origin, + Owner = temporalClient.CurrentServer, Target = _client }, ctx); #if DEBUG == true @@ -255,7 +256,6 @@ namespace SharedLibraryCore.Services #endif }); - await ctx.SaveChangesAsync(); } } diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 34fde6905..874314dd5 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; +using System.Net; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -730,6 +731,53 @@ namespace SharedLibraryCore return string.Format(output, values); } + /// + /// https://stackoverflow.com/questions/8113546/how-to-determine-whether-an-ip-address-in-private/39120248 + /// An extension method to determine if an IP address is internal, as specified in RFC1918 + /// + /// The IP address that will be tested + /// Returns true if the IP is internal, false if it is external + public static bool IsInternal(this IPAddress toTest) + { + if (toTest.ToString().StartsWith("127.0.0")) + { + return true; + } + + byte[] bytes = toTest.GetAddressBytes(); + switch (bytes[0]) + { + case 10: + return true; + case 172: + return bytes[1] < 32 && bytes[1] >= 16; + case 192: + return bytes[1] == 168; + default: + return false; + } + } + + /// + /// retrieves the external IP address of the current running machine + /// + /// + public static async Task GetExternalIP() + { + try + { + using (var wc = new WebClient()) + { + return await wc.DownloadStringTaskAsync("https://api.ipify.org"); + } + } + + catch + { + return null; + } + } + #if DEBUG == true private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo(); diff --git a/WebfrontCore/ViewComponents/ServerListViewComponent.cs b/WebfrontCore/ViewComponents/ServerListViewComponent.cs index 29df5c5ae..f009187dc 100644 --- a/WebfrontCore/ViewComponents/ServerListViewComponent.cs +++ b/WebfrontCore/ViewComponents/ServerListViewComponent.cs @@ -2,6 +2,7 @@ using SharedLibraryCore; using SharedLibraryCore.Dtos; using System.Linq; +using System.Net; namespace WebfrontCore.ViewComponents { @@ -10,6 +11,7 @@ namespace WebfrontCore.ViewComponents public IViewComponentResult Invoke() { var servers = Program.Manager.GetServers(); + var serverInfo = servers.Select(s => new ServerInfo() { Name = s.Hostname, @@ -30,7 +32,8 @@ namespace WebfrontCore.ViewComponents }).ToList(), ChatHistory = s.ChatHistory.ToList(), Online = !s.Throttled, - ConnectProtocolUrl = s.EventParser.URLProtocolFormat.FormatExt(s.IP, s.GetPort()) + IPAddress = $"{(IPAddress.Parse(s.IP).IsInternal() ? Program.Manager.ExternalIPAddress : s.IP)}:{s.GetPort()}", + ConnectProtocolUrl = s.EventParser.URLProtocolFormat.FormatExt(IPAddress.Parse(s.IP).IsInternal() ? Program.Manager.ExternalIPAddress : s.IP, s.GetPort()) }).ToList(); return View("_List", serverInfo); } diff --git a/WebfrontCore/Views/Server/_Server.cshtml b/WebfrontCore/Views/Server/_Server.cshtml index 31b15577d..1b242d818 100644 --- a/WebfrontCore/Views/Server/_Server.cshtml +++ b/WebfrontCore/Views/Server/_Server.cshtml @@ -7,7 +7,8 @@
@Model.Map
diff --git a/WebfrontCore/wwwroot/js/server.js b/WebfrontCore/wwwroot/js/server.js index 29b690e1a..c9c23458c 100644 --- a/WebfrontCore/wwwroot/js/server.js +++ b/WebfrontCore/wwwroot/js/server.js @@ -89,4 +89,10 @@ function refreshClientActivity() { }); } +$(document).ready(function() { + $('.server-join-button').click(function (e) { + $(this).children('.server-header-ip-address').show(); + }); +}) + setInterval(refreshClientActivity, 2000);