diff --git a/Source/ACE.Common/GameConfiguration.cs b/Source/ACE.Common/GameConfiguration.cs index c22871febd..b2ad309619 100644 --- a/Source/ACE.Common/GameConfiguration.cs +++ b/Source/ACE.Common/GameConfiguration.cs @@ -35,5 +35,7 @@ public class GameConfiguration public bool LandblockPreloading { get; set; } public List PreloadedLandblocks { get; set; } + + public HeartbeatSettings Heartbeat { get; set; } } } diff --git a/Source/ACE.Common/HeartbeatSettings.cs b/Source/ACE.Common/HeartbeatSettings.cs new file mode 100644 index 0000000000..67cd2107fd --- /dev/null +++ b/Source/ACE.Common/HeartbeatSettings.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace ACE.Common +{ + public class HeartbeatSettings + { + /// + /// Whether hearbeats are enabled + /// + [System.ComponentModel.DefaultValue(true)] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] + public bool Enabled { get; set; } + + /// + /// The heartbeat endpoint + /// + [System.ComponentModel.DefaultValue("https://treestats-servers.herokuapp.com")] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] + public string Endpoint { get; set; } + + /// + /// The heartbeat interval, in seconds + /// + [System.ComponentModel.DefaultValue(500)] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] + public int Interval { get; set; } + } +} diff --git a/Source/ACE.Server/Managers/HeartbeatManager.cs b/Source/ACE.Server/Managers/HeartbeatManager.cs new file mode 100644 index 0000000000..c8bbde4522 --- /dev/null +++ b/Source/ACE.Server/Managers/HeartbeatManager.cs @@ -0,0 +1,103 @@ +using System; + +using log4net; + +using ACE.Common.Performance; +using System.Net.Http; +using System.Text; +using ACE.Common; +using Newtonsoft.Json; +using System.Threading; + +namespace ACE.Server.Managers +{ + public static class HeartbeatManager + { + private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// The rate at which HeartbeatManager.Tick() executes + /// + private static RateLimiter updateHeartbeatManagerRateLimiter; + + /// + /// Endpoint to send heartbeats to + /// + private static Uri endpoint; + + public static void Initialize() + { + if (!ConfigManager.Config.Server.Heartbeat.Enabled) + { + log.Debug("Not starting HeartbeatManager because it's disabled in config"); + + return; + } + + endpoint = new Uri(ConfigManager.Config.Server.Heartbeat.Endpoint); + updateHeartbeatManagerRateLimiter = new RateLimiter(1, TimeSpan.FromSeconds(ConfigManager.Config.Server.Heartbeat.Interval)); + } + + /// + /// One-off class to help serialize the heartbeat's JSON payload + /// + private class HeartbeatPayload + { + public string WorldName; + public int OnlineCount; + } + + /// + /// Runs at intervals according to config + /// + public static void Tick() + { + + if (updateHeartbeatManagerRateLimiter.GetSecondsToWaitBeforeNextEvent() > 0) + return; + + log.Debug($"HeartbeatManager.Tick()"); + + updateHeartbeatManagerRateLimiter.RegisterEvent(); + + Thread mythread = new Thread(DoHeartbeat); + mythread.Start(); + } + + public static void DoHeartbeat() + { + log.Debug($"HeartbeatManager.DoHeartbeat Called"); + + using (var client = new HttpClient()) + { + HttpResponseMessage response; + + try + { + HeartbeatPayload body = new HeartbeatPayload + { + OnlineCount = PlayerManager.GetOnlineCount(), + WorldName = ConfigManager.Config.Server.WorldName + }; + + HttpContent content = new StringContent(JsonConvert.SerializeObject(body)); + response = client.PostAsync(endpoint, content).Result; + response.EnsureSuccessStatusCode(); + + if (!response.IsSuccessStatusCode) + { + log.Debug($"Heartbeat request failed: {response.Content}"); + } + } + catch (HttpRequestException e) + { + log.Debug($"HttpRequestException while sending Heartbeat {e.Message}"); + } + catch (Exception e) + { + log.Debug($"Exception while sending Heartbeat: {e.Message}"); + } + } + } + } +} diff --git a/Source/ACE.Server/Managers/WorldManager.cs b/Source/ACE.Server/Managers/WorldManager.cs index eeb944cdf9..0c826a4bc7 100644 --- a/Source/ACE.Server/Managers/WorldManager.cs +++ b/Source/ACE.Server/Managers/WorldManager.cs @@ -375,6 +375,8 @@ private static void UpdateWorld() Thread.Sleep(sessionCount == 0 ? 10 : 1); // Relax the CPU more if no sessions are connected Timers.PortalYearTicks += worldTickTimer.Elapsed.TotalSeconds; + + HeartbeatManager.Tick(); } // World has finished operations and concedes the thread to garbage collection diff --git a/Source/ACE.Server/Program.cs b/Source/ACE.Server/Program.cs index 1f8f2d2123..4f1622f832 100644 --- a/Source/ACE.Server/Program.cs +++ b/Source/ACE.Server/Program.cs @@ -196,6 +196,9 @@ public static void Main(string[] args) log.Info("Starting PropertyManager..."); PropertyManager.Initialize(); + log.Info("Starting HeartbeatManager..."); + HeartbeatManager.Initialize(); + log.Info("Initializing GuidManager..."); GuidManager.Initialize();