diff --git a/LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Endpoint.cs b/LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Endpoint.cs index 5fe1486..b22adbd 100644 --- a/LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Endpoint.cs +++ b/LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Endpoint.cs @@ -1,4 +1,4 @@ -using Grapevine; +using Grapevine; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -33,7 +33,7 @@ namespace LightReflectiveMirror.LoadBalancing string address = context.Request.RemoteEndPoint.Address.ToString(); - Console.WriteLine("Received auth req [" + receivedAuthKey + "] == [" + Program.conf.AuthKey+"]"); + Console.WriteLine("Received auth req [" + receivedAuthKey + "] == [" + Program.conf.AuthKey + "]"); // if server is authenticated if (receivedAuthKey != null && address != null && endpointPort != null && gamePort != null && receivedAuthKey == Program.conf.AuthKey) @@ -62,13 +62,13 @@ namespace LightReflectiveMirror.LoadBalancing // collection being modified while iterating. var servers = Program.instance.availableRelayServers.ToList(); - if(servers.Count == 0) + if (servers.Count == 0) { await context.Response.SendResponseAsync(HttpStatusCode.ServiceUnavailable); return; } - KeyValuePair lowest = new(new RelayAddress { Address = "Dummy" }, new RelayStats { ConnectedClients = int.MaxValue }); + KeyValuePair lowest = new(new RelayAddress { Address = "Dummy" }, new RelayServerInfo { ConnectedClients = int.MaxValue }); for (int i = 0; i < servers.Count; i++) { @@ -84,8 +84,8 @@ namespace LightReflectiveMirror.LoadBalancing { // ping server to ensure its online. var chosenServer = await Program.instance.ManualPingServer(lowest.Key.Address, lowest.Key.EndpointPort); - - if(chosenServer.HasValue) + + if (chosenServer.HasValue) await context.Response.SendResponseAsync(JsonConvert.SerializeObject(lowest.Key)); else await context.Response.SendResponseAsync(HttpStatusCode.BadGateway); @@ -95,8 +95,40 @@ namespace LightReflectiveMirror.LoadBalancing await context.Response.SendResponseAsync(HttpStatusCode.InternalServerError); } } + + /// + /// Returns all the servers on all the relay nodes. + /// + /// + /// + [RestRoute("Get", "/api/masterlist/")] + public async Task GetMasterServerList(IHttpContext context) + { + var relays = Program.instance.availableRelayServers.ToList(); + List masterList = new(); + + foreach (var relay in relays) + { + var serversOnRelay = await Program.instance.GetServerListFromIndividualRelay(relay.Key.Address, relay.Key.EndpointPort); + + if(serversOnRelay != null) + { + masterList.AddRange(serversOnRelay); + } + else { continue; } + } + + // we have servers, send em! + if (masterList.Any()) + await context.Response.SendResponseAsync(JsonConvert.SerializeObject(masterList)); + // no servers or maybe no relays, fuck you + else + await context.Response.SendResponseAsync(HttpStatusCode.NoContent); + } } + #region Startup + public class EndpointServer { public bool Start(ushort port = 7070) @@ -144,5 +176,8 @@ namespace LightReflectiveMirror.LoadBalancing return null; } + #endregion + } + } diff --git a/LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Program.cs b/LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Program.cs index 1cc7d0a..fbf69dd 100644 --- a/LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Program.cs +++ b/LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Program.cs @@ -14,7 +14,7 @@ namespace LightReflectiveMirror.LoadBalancing /// Keeps track of all available relays. /// Key is server address, value is CCU. /// - public Dictionary availableRelayServers = new(); + public Dictionary availableRelayServers = new(); private int _pingDelay = 10000; const string API_PATH = "/api/stats"; @@ -64,7 +64,7 @@ namespace LightReflectiveMirror.LoadBalancing availableRelayServers.Add(new RelayAddress { Port = port, EndpointPort = endpointPort, Address = serverIP }, stats.Value); } - public async Task ManualPingServer(string serverIP, ushort port) + public async Task ManualPingServer(string serverIP, ushort port) { using (WebClient wc = new WebClient()) { @@ -72,7 +72,7 @@ namespace LightReflectiveMirror.LoadBalancing { string receivedStats = await wc.DownloadStringTaskAsync($"http://{serverIP}:{port}{API_PATH}"); - return JsonConvert.DeserializeObject(receivedStats); + return JsonConvert.DeserializeObject(receivedStats); } catch(Exception e) { @@ -82,6 +82,23 @@ namespace LightReflectiveMirror.LoadBalancing } } + public async Task> GetServerListFromIndividualRelay(string serverIP, ushort port) + { + using (WebClient wc = new WebClient()) + { + try + { + string receivedStats = await wc.DownloadStringTaskAsync($"http://{serverIP}:{port}/api/servers"); + return JsonConvert.DeserializeObject>(receivedStats); + } + catch (Exception e) + { + // Server failed to respond + return null; + } + } + } + async Task PingServers() { while (true) @@ -100,7 +117,7 @@ namespace LightReflectiveMirror.LoadBalancing try { var serverStats = wc.DownloadString(url); - var deserializedData = JsonConvert.DeserializeObject(serverStats); + var deserializedData = JsonConvert.DeserializeObject(serverStats); WriteLogMessage("Server " + keys[i].Address + " still exists, keeping in collection."); @@ -137,7 +154,7 @@ namespace LightReflectiveMirror.LoadBalancing | | | | | | / \ | | | | w /| | | | | | | / /\ \ | | | | | \ | |____ | |__| | / ____ \ | |__| | m m copyright monkesoft 2021 - |______| \____/ /_/ \_\ |_____/ + |______| \____/ /_/ \_\ |_____/ ____ _ _ _ _____ ______ _____ | _ \ /\ | | /\ | \ | | / ____| | ____| | __ \ | |_) | / \ | | / \ | \| | | | | |__ | |__) | @@ -165,8 +182,9 @@ namespace LightReflectiveMirror.LoadBalancing } + // for stats [Serializable] - public struct RelayStats + public struct RelayServerInfo { public int ConnectedClients; public int RoomCount; @@ -174,6 +192,7 @@ namespace LightReflectiveMirror.LoadBalancing public TimeSpan Uptime; } + // container for relay address info [Serializable] public struct RelayAddress { @@ -182,4 +201,19 @@ namespace LightReflectiveMirror.LoadBalancing public string Address; } + // fuck you + [Serializable] + public struct Room + { + public int serverId; + public int hostId; + public string serverName; + public string serverData; + public bool isPublic; + public int maxPlayers; + public List clients; + + public RelayAddress relayInfo; + } + } diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program.cs index e672306..bc4d8f3 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program.cs @@ -26,7 +26,7 @@ namespace LightReflectiveMirror private MethodInfo _lateUpdateMethod; private DateTime _startupTime; - + public static string publicIP; private List _currentConnections = new List(); public Dictionary NATConnections = new Dictionary(); private BiDictionary _pendingNATPunches = new BiDictionary(); @@ -51,6 +51,7 @@ namespace LightReflectiveMirror WriteTitle(); instance = this; _startupTime = DateTime.Now; + publicIP = new WebClient().DownloadString("http://icanhazip.com").Replace("\\r\\n", "").Replace("\\n", "").Trim(); if (!File.Exists(CONFIG_PATH)) { diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler.cs index e91dad3..1fb61e6 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler.cs @@ -233,9 +233,7 @@ namespace LightReflectiveMirror void CreateRoom(int clientId, int maxPlayers, string serverName, bool isPublic, string serverData, bool useDirectConnect, string hostLocalIP, bool useNatPunch, int port) { LeaveRoom(clientId); - - IPEndPoint hostIP = null; - Program.instance.NATConnections.TryGetValue(clientId, out hostIP); + Program.instance.NATConnections.TryGetValue(clientId, out IPEndPoint hostIP); Room room = new Room { @@ -245,6 +243,12 @@ namespace LightReflectiveMirror isPublic = isPublic, serverData = serverData, clients = new List(), + + // hard coded for now REMEMBER TO UN-HARDCODE RETARD + // this is needed for load balancer to know which server this room + // belongs to + relayInfo = new RelayAddress { Address = Program.publicIP, Port = 7777, EndpointPort = Program.conf.EndpointPort }, + serverId = GetRandomServerID(), hostIP = hostIP, hostLocalIP = hostLocalIP, diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Room.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Room.cs index e2d4973..527e8ed 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Room.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Room.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.Net; @@ -14,6 +15,9 @@ namespace LightReflectiveMirror public bool isPublic; public int maxPlayers; public List clients; + + public RelayAddress relayInfo; + [JsonIgnore] public bool supportsDirectConnect = false; [JsonIgnore] @@ -25,4 +29,12 @@ namespace LightReflectiveMirror [JsonIgnore] public int port; } + + [Serializable] + public struct RelayAddress + { + public ushort Port; + public ushort EndpointPort; + public string Address; + } } diff --git a/UnityTransport/LightReflectiveMirrorTransport.cs b/UnityTransport/LightReflectiveMirrorTransport.cs index 3fd1034..72d85b4 100644 --- a/UnityTransport/LightReflectiveMirrorTransport.cs +++ b/UnityTransport/LightReflectiveMirrorTransport.cs @@ -44,7 +44,7 @@ namespace LightReflectiveMirror [Header("Server List")] public UnityEvent serverListUpdated; - public List relayServerList { private set; get; } = new List(); + public List relayServerList { private set; get; } = new List(); [Header("Server Information")] public int serverId = -1; @@ -472,7 +472,61 @@ namespace LightReflectiveMirror IEnumerator GetServerList() { - string uri = $"http://{serverIP}:{endpointServerPort}/api/compressed/servers"; + if (!useLoadBalancer) + { + string uri = $"http://{serverIP}:{endpointServerPort}/api/compressed/servers"; + + using (UnityWebRequest webRequest = UnityWebRequest.Get(uri)) + { + // Request and wait for the desired page. + yield return webRequest.SendWebRequest(); + var result = webRequest.downloadHandler.text; + +#if UNITY_2020_1_OR_NEWER + switch (webRequest.result) + { + case UnityWebRequest.Result.ConnectionError: + case UnityWebRequest.Result.DataProcessingError: + case UnityWebRequest.Result.ProtocolError: + Debug.LogWarning("LRM | Network Error while retreiving the server list!"); + break; + + case UnityWebRequest.Result.Success: + relayServerList?.Clear(); + relayServerList = JsonConvert.DeserializeObject>(result.Decompress()); + serverListUpdated?.Invoke(); + break; + } +#else + if (webRequest.isNetworkError || webRequest.isHttpError) + { + Debug.LogWarning("LRM | Network Error while retreiving the server list!"); + } + else + { + relayServerList?.Clear(); + relayServerList = JsonConvert.DeserializeObject>(result.Decompress()); + serverListUpdated?.Invoke(); + } +#endif + } + } + else // get master list from load balancer + { + yield return StartCoroutine(RetrieveMasterServerListFromLoadBalancer()); + } + + } + + /// + /// Gets master list from the LB. + /// This can be optimized but for now it is it's + /// own separate method, so i can understand wtf is going on :D + /// + /// + IEnumerator RetrieveMasterServerListFromLoadBalancer() + { + string uri = $"http://{loadBalancerAddress}:{loadBalancerPort}/api/masterlist/"; using (UnityWebRequest webRequest = UnityWebRequest.Get(uri)) { @@ -491,7 +545,7 @@ namespace LightReflectiveMirror case UnityWebRequest.Result.Success: relayServerList?.Clear(); - relayServerList = JsonConvert.DeserializeObject>(result.Decompress()); + relayServerList = JsonConvert.DeserializeObject>(result); serverListUpdated?.Invoke(); break; } @@ -503,7 +557,7 @@ namespace LightReflectiveMirror else { relayServerList?.Clear(); - relayServerList = JsonConvert.DeserializeObject>(result.Decompress()); + relayServerList = JsonConvert.DeserializeObject>(result); serverListUpdated?.Invoke(); } #endif @@ -842,13 +896,15 @@ namespace LightReflectiveMirror } [Serializable] - public struct RelayServerInfo + public struct Room { public string serverName; public int currentPlayers; public int maxPlayers; public int serverId; public string serverData; + + public RelayAddress relayInfo; } [Serializable] @@ -858,4 +914,5 @@ namespace LightReflectiveMirror public ushort EndpointPort; public string Address; } + }