mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Add automatic hub advertisement.
This commit is contained in:
@@ -12,6 +12,7 @@ using Robust.Server.Log;
|
||||
using Robust.Server.Placement;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Server.Scripting;
|
||||
using Robust.Server.ServerHub;
|
||||
using Robust.Server.ServerStatus;
|
||||
using Robust.Server.Utility;
|
||||
using Robust.Server.ViewVariables;
|
||||
@@ -78,6 +79,7 @@ namespace Robust.Server
|
||||
[Dependency] private readonly IRuntimeLog runtimeLog = default!;
|
||||
[Dependency] private readonly IModLoaderInternal _modLoader = default!;
|
||||
[Dependency] private readonly IWatchdogApi _watchdogApi = default!;
|
||||
[Dependency] private readonly HubManager _hubManager = default!;
|
||||
[Dependency] private readonly IScriptHost _scriptHost = default!;
|
||||
[Dependency] private readonly IMetricsManager _metricsManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
@@ -353,6 +355,7 @@ namespace Robust.Server
|
||||
_modLoader.BroadcastRunLevel(ModRunLevel.PostInit);
|
||||
|
||||
IoCManager.Resolve<IStatusHost>().Start();
|
||||
IoCManager.Resolve<HubManager>().Start();
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit += ProcessExiting;
|
||||
|
||||
@@ -627,6 +630,7 @@ namespace Robust.Server
|
||||
}
|
||||
|
||||
_watchdogApi.Heartbeat();
|
||||
_hubManager.Heartbeat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
132
Robust.Server/ServerHub/HubManager.cs
Normal file
132
Robust.Server/ServerHub/HubManager.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Server.ServerHub;
|
||||
|
||||
internal sealed class HubManager
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly ILogManager _log = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
private string? _advertiseUrl;
|
||||
private string _masterUrl = "";
|
||||
private TimeSpan _nextPing;
|
||||
private TimeSpan _interval;
|
||||
|
||||
private bool _active;
|
||||
private bool _firstAdvertisement = true;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public HubManager()
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
|
||||
var assembly = typeof(HubManager).Assembly.GetName();
|
||||
if (assembly is { Name: { } name, Version: { } version })
|
||||
_httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(name, version.ToString()));
|
||||
}
|
||||
|
||||
public async void Start()
|
||||
{
|
||||
_sawmill = _log.GetSawmill("hub");
|
||||
|
||||
var activate = _cfg.GetCVar(CVars.HubAdvertise);
|
||||
if (!activate)
|
||||
return;
|
||||
|
||||
_cfg.OnValueChanged(CVars.HubAdvertiseInterval, i => _interval = TimeSpan.FromSeconds(i), true);
|
||||
_cfg.OnValueChanged(CVars.HubMasterUrl, s => _masterUrl = s, true);
|
||||
|
||||
var url = _cfg.GetCVar(CVars.HubServerUrl);
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
_sawmill.Info("hub.server_url unset. Trying to determine IP address automatically...");
|
||||
try
|
||||
{
|
||||
url = await GuessAddress();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_sawmill.Log(LogLevel.Error, e, "Failed to determine address for hub advertisement!");
|
||||
return;
|
||||
}
|
||||
|
||||
_sawmill.Info("Guessed server address to be {ServerHubAddress}", url);
|
||||
}
|
||||
|
||||
_active = true;
|
||||
_advertiseUrl = url;
|
||||
}
|
||||
|
||||
public void Heartbeat()
|
||||
{
|
||||
if (!_active || _advertiseUrl == null)
|
||||
return;
|
||||
|
||||
if (_nextPing > _timing.RealTime)
|
||||
return;
|
||||
|
||||
_nextPing = _timing.RealTime + _interval;
|
||||
|
||||
SendPing();
|
||||
}
|
||||
|
||||
private async void SendPing()
|
||||
{
|
||||
DebugTools.AssertNotNull(_advertiseUrl);
|
||||
|
||||
var apiUrl = $"{_masterUrl}api/servers/advertise";
|
||||
|
||||
try
|
||||
{
|
||||
using var response = await _httpClient.PostAsJsonAsync(apiUrl, new AdvertiseRequest(_advertiseUrl!));
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var errorText = await response.Content.ReadAsStringAsync();
|
||||
_sawmill.Log(
|
||||
LogLevel.Error,
|
||||
"Error status while advertising server: [{StatusCode}] {Response}",
|
||||
response.StatusCode,
|
||||
errorText);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_firstAdvertisement)
|
||||
{
|
||||
_sawmill.Info("Successfully advertised to hub with address {ServerHubAddress}", _advertiseUrl);
|
||||
_firstAdvertisement = false;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_sawmill.Log(LogLevel.Error, e, $"Exception while trying to advertise server to hub");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string?> GuessAddress()
|
||||
{
|
||||
var ipifyUrl = _cfg.GetCVar(CVars.HubIpifyUrl);
|
||||
|
||||
var req = await _httpClient.GetFromJsonAsync<IpResponse>(ipifyUrl);
|
||||
|
||||
return $"ss14://{req!.Ip}:{_cfg.GetCVar(CVars.NetPort)}/";
|
||||
}
|
||||
|
||||
private sealed record IpResponse(string Ip);
|
||||
|
||||
// ReSharper disable once NotAccessedPositionalProperty.Local
|
||||
private sealed record AdvertiseRequest(string Address);
|
||||
}
|
||||
@@ -11,6 +11,7 @@ using Robust.Server.Player;
|
||||
using Robust.Server.Prototypes;
|
||||
using Robust.Server.Reflection;
|
||||
using Robust.Server.Scripting;
|
||||
using Robust.Server.ServerHub;
|
||||
using Robust.Server.ServerStatus;
|
||||
using Robust.Server.ViewVariables;
|
||||
using Robust.Shared;
|
||||
@@ -75,6 +76,7 @@ namespace Robust.Server
|
||||
IoCManager.Register<IAuthManager, AuthManager>();
|
||||
IoCManager.Register<IPhysicsManager, PhysicsManager>();
|
||||
IoCManager.Register<IBqlQueryManager, BqlQueryManager>();
|
||||
IoCManager.Register<HubManager, HubManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,14 @@ welcomemsg = "Welcome to the server!"
|
||||
# This literally works by checking if address == 127.0.0.1 || address == ::1
|
||||
loginlocal = true
|
||||
|
||||
[hub]
|
||||
# Set to true to show this server on the public server list
|
||||
advertise = false
|
||||
# URL of your server. Fill this in if you have a domain name,
|
||||
# want to use HTTPS (with a reverse proxy), or other advanced scenarios.
|
||||
# Must be in the form of an ss14:// or ss14s:// URI pointing to the status API.
|
||||
server_url = ""
|
||||
|
||||
[build]
|
||||
# *Absolutely all of these can be supplied using a "build.json" file*
|
||||
# For further information, see https://github.com/space-wizards/space-station-14/blob/master/Tools/gen_build_info.py
|
||||
|
||||
@@ -650,5 +650,44 @@ namespace Robust.Shared
|
||||
|
||||
public static readonly CVarDef<float> MidiVolume =
|
||||
CVarDef.Create("midi.volume", 0f, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
/*
|
||||
* HUB
|
||||
* CVars related to public master server hub
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Whether to advertise this server to the public server hub.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> HubAdvertise =
|
||||
CVarDef.Create("hub.advertise", false, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// URL of the master hub server to advertise to.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<string> HubMasterUrl =
|
||||
CVarDef.Create("hub.master_url", "https://central.spacestation14.io/hub/", CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// URL of this server to advertise.
|
||||
/// This is automatically inferred by the hub server based on IP address if left empty,
|
||||
/// but if you want to specify a domain or use <c>ss14://</c> you should specify this manually.
|
||||
/// You also have to set this if you change status.bind.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<string> HubServerUrl =
|
||||
CVarDef.Create("hub.server_url", "", CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// URL to use to automatically try to detect IPv4 address.
|
||||
/// This is only used if hub.server_url is unset.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<string> HubIpifyUrl =
|
||||
CVarDef.Create("hub.ipify_url", "https://api.ipify.org?format=json", CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// How long to wait between advertise pings to the hub server.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> HubAdvertiseInterval =
|
||||
CVarDef.Create("hub.advertise_interval", 120, CVar.SERVERONLY);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user