Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add public HTTP API endpoints for centralized app #22

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion EchoRelay.App/Forms/Controls/ServerInfoControl.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using EchoRelay.Core.Server;
using EchoRelay.Core.Monitoring;
using EchoRelay.Core.Utils;
using Newtonsoft.Json;
using Server = EchoRelay.Core.Server.Server;

namespace EchoRelay.App.Forms.Controls
{
public partial class ServerInfoControl : UserControl
{
ApiManager _apiManager = ApiManager.Instance;
public ServerInfoControl()
{
InitializeComponent();
Expand Down Expand Up @@ -36,6 +38,16 @@ public void UpdateServerInfo(Server? server, bool updateServiceConfig)
rtbGeneratedServiceConfig.Text = "";
}
}


_apiManager.peerStatsObject.ServerIp = server?.PublicIPAddress?.ToString() ?? "localhost";
_apiManager.peerStatsObject.Login = server?.LoginService.Peers.Count ?? 0;
_apiManager.peerStatsObject.Matching = server?.MatchingService.Peers.Count ?? 0;
_apiManager.peerStatsObject.Config = server?.ConfigService.Peers.Count ?? 0;
_apiManager.peerStatsObject.Transaction = server?.TransactionService.Peers.Count ?? 0;
_apiManager.peerStatsObject.ServerDb = server?.ServerDBService.Peers.Count ?? 0;
Task.Run(() => _apiManager.PeerStats.EditPeerStats(_apiManager.peerStatsObject, server?.PublicIPAddress?.ToString() ?? "localhost"));

}

private void btnCopyServiceConfig_Click(object sender, EventArgs e)
Expand Down
9 changes: 9 additions & 0 deletions EchoRelay.App/Forms/MainWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using EchoRelay.Core.Monitoring;
using Server = EchoRelay.Core.Server.Server;

namespace EchoRelay
{
Expand All @@ -36,6 +38,8 @@ public partial class MainWindow : Form
/// The websocket server used to power central game services.
/// </summary>
public Server Server { get; set; }

public ApiManager apiManager { get; set; }

/// <summary>
/// The UI editors for different storage resources.
Expand Down Expand Up @@ -130,6 +134,8 @@ public MainWindow()
Server.ServerDBService.Registry.OnGameServerRegistered += Registry_OnGameServerRegistered;
Server.ServerDBService.Registry.OnGameServerUnregistered += Registry_OnGameServerUnregistered;
Server.ServerDBService.OnGameServerRegistrationFailure += ServerDBService_OnGameServerRegistrationFailure; ;

apiManager = ApiManager.Instance;
}
#endregion

Expand Down Expand Up @@ -360,6 +366,9 @@ private void Registry_OnGameServerRegistered(EchoRelay.Core.Server.Services.Serv
// Update server count on the game server tab.
tabGameServers.Text = $"Game Servers ({gameServersControl.GameServerCount})";

apiManager.peerStatsObject.GameServers = gameServersControl.GameServerCount;
Task.Run(() => apiManager.PeerStats.EditPeerStats(apiManager.peerStatsObject, Server.PublicIPAddress?.ToString() ?? "localhost"));

AppendLogText($"[{gameServer.Peer.Service.Name}] client({gameServer.Peer.Address}:{gameServer.Peer.Port}) registered game server (server_id={gameServer.ServerId}, region_symbol={gameServer.RegionSymbol}, version_lock={gameServer.VersionLock}, endpoint=<{gameServer.ExternalAddress}:{gameServer.Port}>)\n");
});
}
Expand Down
78 changes: 69 additions & 9 deletions EchoRelay.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
using Microsoft.AspNetCore.Components.Web;
using Newtonsoft.Json;
using System.Reflection;
using System.Runtime.InteropServices;
using EchoRelay.Core.Monitoring;
using Server = EchoRelay.Core.Server.Server;

namespace EchoRelay.Cli
{
Expand All @@ -20,11 +23,13 @@ class Program
/// <summary>
/// The instance of the server hosting central services.
/// </summary>
private static Server Server;
private static Server? Server;
/// <summary>
/// The update timer used to trigger a peer stats update on a given interval.
/// </summary>
private static System.Timers.Timer? peerStatsUpdateTimer;

private static ApiManager? apiManager;
/// <summary>
/// The time that the server was started.
/// </summary>
Expand All @@ -33,6 +38,22 @@ class Program
/// A mutex lock object to be used when printing to console, to avoid color collisions.
/// </summary>
private static object _printLock = new object();

[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);

private delegate bool EventHandler(CtrlType sig);
private static EventHandler? consoleCloseHandler;

// Enum to represent different CtrlTypes
private enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}

/// <summary>
/// The CLI argument options for the application.
Expand Down Expand Up @@ -135,6 +156,8 @@ static void Main(string[] args)
)
);

apiManager = ApiManager.Instance;

// Set up all event handlers.
Server.OnServerStarted += Server_OnServerStarted;
Server.OnServerStopped += Server_OnServerStopped;
Expand All @@ -145,6 +168,10 @@ static void Main(string[] args)
Server.ServerDBService.Registry.OnGameServerRegistered += Registry_OnGameServerRegistered;
Server.ServerDBService.Registry.OnGameServerUnregistered += Registry_OnGameServerUnregistered;
Server.ServerDBService.OnGameServerRegistrationFailure += ServerDBService_OnGameServerRegistrationFailure;

// Set up the event handler for the console close event
consoleCloseHandler += new EventHandler(ConsoleCloseHandler);
SetConsoleCtrlHandler(consoleCloseHandler, true);

// Set up all verbose event handlers.
if (options.Verbose)
Expand Down Expand Up @@ -183,6 +210,8 @@ private static void Server_OnServerStarted(Server server)
}
}

updateServerInfo();

// Start the peer stats update timer
startedTime = DateTime.UtcNow;
peerStatsUpdateTimer = new System.Timers.Timer(Options!.StatsUpdateInterval);
Expand All @@ -193,14 +222,14 @@ private static void Server_OnServerStarted(Server server)
private static void PeerStatsUpdateTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
{
Info($"[PEERSTATS] " +
$"elapsed: {(DateTime.UtcNow - startedTime)}, " +
$"gameservers: {Server.ServerDBService.Registry.RegisteredGameServers.Count}, " +
$"login: {Server.LoginService.Peers.Count}, " +
$"config: {Server.ConfigService.Peers.Count}, " +
$"matching: {Server.MatchingService.Peers.Count}, " +
$"serverdb: {Server.ServerDBService.Peers.Count}, " +
$"transaction: {Server.TransactionService.Peers.Count}"
);
$"elapsed: {(DateTime.UtcNow - startedTime)}, " +
$"gameservers: {Server.ServerDBService.Registry.RegisteredGameServers.Count}, " +
$"login: {Server.LoginService.Peers.Count}, " +
$"config: {Server.ConfigService.Peers.Count}, " +
$"matching: {Server.MatchingService.Peers.Count}, " +
$"serverdb: {Server.ServerDBService.Peers.Count}, " +
$"transaction: {Server.TransactionService.Peers.Count}"
);
}

private static void Server_OnServerStopped(Server server)
Expand All @@ -210,20 +239,36 @@ private static void Server_OnServerStopped(Server server)

// Print our server stopped message
Info("[SERVER] Server stopped");

updateServerInfo();
}

private static void Server_OnAuthorizationResult(Server server, System.Net.IPEndPoint client, bool authorized)
{
if(!authorized)
Error($"[SERVER] client({client.Address}:{client.Port}) failed authorization");
}

private static void updateServerInfo()
{
apiManager.peerStatsObject.ServerIp = Server?.PublicIPAddress?.ToString() ?? "localhost";
apiManager.peerStatsObject.Login = Server?.LoginService.Peers.Count;
apiManager.peerStatsObject.Matching = Server?.MatchingService.Peers.Count;
apiManager.peerStatsObject.Config = Server?.ConfigService.Peers.Count;
apiManager.peerStatsObject.Transaction = Server?.TransactionService.Peers.Count;
apiManager.peerStatsObject.ServerDb = Server?.ServerDBService.Peers.Count;
apiManager.peerStatsObject.GameServers = Server?.ServerDBService.Registry.RegisteredGameServers.Count;
Task.Run(() => apiManager.PeerStats.EditPeerStats(apiManager.peerStatsObject, apiManager.peerStatsObject.ServerIp));
}
private static void Server_OnServicePeerConnected(Core.Server.Services.Service service, Core.Server.Services.Peer peer)
{
Info($"[{service.Name}] client({peer.Address}:{peer.Port}) connected");
updateServerInfo();
}
private static void Server_OnServicePeerDisconnected(Core.Server.Services.Service service, Core.Server.Services.Peer peer)
{
Info($"[{service.Name}] client({peer.Address}:{peer.Port}) disconnected");
updateServerInfo();
}
private static void Server_OnServicePeerAuthenticated(Core.Server.Services.Service service, Core.Server.Services.Peer peer, Core.Game.XPlatformId userId)
{
Expand All @@ -233,11 +278,14 @@ private static void Server_OnServicePeerAuthenticated(Core.Server.Services.Servi
private static void Registry_OnGameServerRegistered(Core.Server.Services.ServerDB.RegisteredGameServer gameServer)
{
Info($"[{gameServer.Peer.Service.Name}] client({gameServer.Peer.Address}:{gameServer.Peer.Port}) registered game server (server_id={gameServer.ServerId}, region_symbol={gameServer.RegionSymbol}, version_lock={gameServer.VersionLock}, endpoint=<{gameServer.ExternalAddress}:{gameServer.Port}>)");
updateServerInfo();
}

private static void Registry_OnGameServerUnregistered(Core.Server.Services.ServerDB.RegisteredGameServer gameServer)
{
Info($"[{gameServer.Peer.Service.Name}] client({gameServer.Peer.Address}:{gameServer.Peer.Port}) unregistered game server (server_id={gameServer.ServerId}, region_symbol={gameServer.RegionSymbol}, version_lock={gameServer.VersionLock}, endpoint=<{gameServer.ExternalAddress}:{gameServer.Port}>)");
updateServerInfo();

}
private static void ServerDBService_OnGameServerRegistrationFailure(Peer peer, Core.Server.Messages.ServerDB.ERGameServerRegistrationRequest registrationRequest, string failureMessage)
{
Expand Down Expand Up @@ -306,5 +354,17 @@ private static void Debug(string msg)
Console.ResetColor();
}
}

// Handler for the console close event
private static bool ConsoleCloseHandler(CtrlType sig)
{
Console.WriteLine("Console is closing. Performing cleanup...");
Server?.Stop();

Thread.Sleep(1500);

// Allow the program to exit
return true;
}
}
}
42 changes: 42 additions & 0 deletions EchoRelay.Core/Monitoring/ApiClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Security.Cryptography;
using System.Text;

namespace EchoRelay.Core.Monitoring;

//TO DO : Encrypt data
public class ApiClient
{
private readonly HttpClient _httpClient;

public ApiClient(string baseUrl)
{
_httpClient = new HttpClient
{
BaseAddress = new Uri(baseUrl)
};
}

//TODO encrypt data to avoid people to send fake data
public async Task<string> PostMonitoringData(string endpoint, string data)
{
HttpContent content = new StringContent(data, Encoding.UTF8, "application/json");
HttpResponseMessage response = await _httpClient.PostAsync(endpoint, content);

if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
throw new Exception($"API request failed with status code: {response.StatusCode}");
}

public async Task DeleteMonitoringData(string endpoint)
{
HttpResponseMessage response = await _httpClient.DeleteAsync(endpoint);

if (!response.IsSuccessStatusCode)
{
throw new Exception($"DELETE request failed with status code: {response.StatusCode}");
}
}

}
41 changes: 41 additions & 0 deletions EchoRelay.Core/Monitoring/ApiManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Security.Cryptography;

namespace EchoRelay.Core.Monitoring;

public class ApiManager
{

/// <summary>
/// Uri to the monitoring API
/// </summary>
public string URI { get; } = "http://localhost:3000/api/";
//public string URI { get; } = "http://51.75.140.182:3000/api/";

public PeerStatsObject peerStatsObject;
/// <summary>
/// Public key to encrypt data
/// </summary>
public ApiClient Monitoring { get; }

public Server Server { get; }

public GameServer GameServer { get; }
public PeerStats PeerStats { get; }

private static ApiManager instance = new ApiManager();

private ApiManager()
{
Monitoring = new ApiClient(URI);
GameServer = new GameServer(Monitoring);
PeerStats = new PeerStats(Monitoring);
Server = new Server(Monitoring);
peerStatsObject = new PeerStatsObject();
}

// Method to get the singleton instance
public static ApiManager Instance
{
get { return instance; }
}
}
63 changes: 63 additions & 0 deletions EchoRelay.Core/Monitoring/GameServer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Newtonsoft.Json;

namespace EchoRelay.Core.Monitoring;

public class GameServer
{
private readonly ApiClient _apiClient;

public GameServer(ApiClient apiClient)
{
_apiClient = apiClient;
}

public async Task DeleteGameServerAsync(string sessionId)
{
// Define the endpoint for deleting a game server with the sessionID
string endpoint = $"deleteGameServer/{sessionId}";

try
{
await _apiClient.DeleteMonitoringData(endpoint);
Console.WriteLine($"Game server with session ID {sessionId} deleted successfully from monitoring.");
}
catch (Exception ex)
{
Console.WriteLine($"Error deleting the game server from monitoring: {ex.Message}");
}
}

public async Task AddGameServerAsync(GameServerObject jsonObject)
{
// Create a StringContent with the JSON data and set the content type
string jsonData = JsonConvert.SerializeObject(jsonObject);
string endpoint = "addGameServer/";

try
{
await _apiClient.PostMonitoringData(endpoint, jsonData);
Console.WriteLine($"Game server successfully added to monitoring.");
}
catch (Exception ex)
{
Console.WriteLine($"Error adding the game server from monitoring: {ex.Message}");
}
}

public async Task EditGameServer(GameServerObject jsonObject, string gameServerID)
{
// Create a StringContent with the JSON data and set the content type
string jsonData = JsonConvert.SerializeObject(jsonObject);
string endpoint = $"updateGameServer/{gameServerID}";

try
{
await _apiClient.PostMonitoringData(endpoint, jsonData);
Console.WriteLine($"Game server successfully edited in monitoring.");
}
catch (Exception ex)
{
Console.WriteLine($"Error editing the game server in monitoring: {ex.Message}");
}
}
}
Loading