Skip to content
This repository has been archived by the owner on Sep 5, 2022. It is now read-only.

Commit

Permalink
Added Regions to Load Balancer Setup.
Browse files Browse the repository at this point in the history
  • Loading branch information
Derek-R-S committed Apr 7, 2021
1 parent 36362af commit 14ea624
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ namespace LightReflectiveMirror.LoadBalancing
[Serializable]
public struct RelayServerInfo
{
public int ConnectedClients;
public int RoomCount;
public int PublicRoomCount;
public TimeSpan Uptime;
public int connectedClients;
public int roomCount;
public int publicRoomCount;
public TimeSpan uptime;

[JsonIgnore]
public List<Room> serversConnectedToRelay;
Expand All @@ -20,21 +20,22 @@ public struct RelayServerInfo
[Serializable]
internal struct LoadBalancerStats
{
public int NodeCount;
public TimeSpan Uptime;
public int nodeCount;
public TimeSpan uptime;
public long CCU;
public long TotalServerCount;
public long totalServerCount;
}

// container for relay address info
[JsonObject(MemberSerialization.OptOut)]
public struct RelayAddress
{
public ushort Port;
public ushort EndpointPort;
public string Address;
public ushort port;
public ushort endpointPort;
public string address;
public LRMRegions serverRegion;
[JsonIgnore]
public string EndpointAddress;
public string endpointAddress;
}

[Serializable]
Expand All @@ -50,4 +51,6 @@ public struct Room

public RelayAddress relayInfo;
}

public enum LRMRegions { Any, NorthAmerica, SouthAmerica, Europe, Asia, Africa, Oceania }
}
127 changes: 111 additions & 16 deletions LoadBalancerProject-DONT-IMPORT-INTO-UNITY/LRM_LoadBalancer/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,30 @@ namespace LightReflectiveMirror.LoadBalancing
[RestResource]
public class Endpoint
{
public static string cachedServerList = "[]";
public static string allCachedServers = "[]";
public static string NorthAmericaCachedServers = "[]";
public static string SouthAmericaCachedServers = "[]";
public static string EuropeCachedServers = "[]";
public static string AsiaCachedServers = "[]";
public static string AfricaCachedServers = "[]";
public static string OceaniaCachedServers = "[]";

private static List<Room> northAmericaServers = new();
private static List<Room> southAmericaServers = new();
private static List<Room> europeServers = new();
private static List<Room> africaServers = new();
private static List<Room> asiaServers = new();
private static List<Room> oceaniaServers = new();
private static List<Room> allServers = new();

private LoadBalancerStats _stats
{
get => new()
{
NodeCount = Program.instance.availableRelayServers.Count,
Uptime = DateTime.Now - Program.startupTime,
nodeCount = Program.instance.availableRelayServers.Count,
uptime = DateTime.Now - Program.startupTime,
CCU = Program.instance.GetTotalCCU(),
TotalServerCount = Program.instance.GetTotalServers(),
totalServerCount = Program.instance.GetTotalServers(),
};
}

Expand All @@ -45,20 +59,22 @@ public async Task ReceiveAuthKey(IHttpContext context)
string endpointPort = req.Headers["x-EndpointPort"];
string gamePort = req.Headers["x-GamePort"];
string publicIP = req.Headers["x-PIP"];
string region = req.Headers["x-Region"];
int regionId = 1;

string address = context.Request.RemoteEndPoint.Address.ToString();
Logger.WriteLogMessage("Received auth req [" + receivedAuthKey + "] == [" + Program.conf.AuthKey + "]");

// if server is authenticated
if (receivedAuthKey != null && address != null && endpointPort != null && gamePort != null && receivedAuthKey == Program.conf.AuthKey)
if (receivedAuthKey != null && region != null && int.TryParse(region, out regionId) && address != null && endpointPort != null && gamePort != null && receivedAuthKey == Program.conf.AuthKey)
{
Logger.WriteLogMessage($"Server accepted: {address}:{gamePort}");

try
{
var _gamePort = Convert.ToUInt16(gamePort);
var _endpointPort = Convert.ToUInt16(endpointPort);
await Program.instance.AddServer(address, _gamePort, _endpointPort, publicIP);
await Program.instance.AddServer(address, _gamePort, _endpointPort, publicIP, regionId);
}
catch
{
Expand All @@ -82,20 +98,66 @@ public async Task ServerListUpdate(IHttpContext context)
// Dont allow unauthorizated access waste computing resources.
string auth = context.Request.Headers["Authorization"];

if(!string.IsNullOrEmpty(auth) && auth == Program.conf.AuthKey)
if (!string.IsNullOrEmpty(auth) && auth == Program.conf.AuthKey)
{
var relays = Program.instance.availableRelayServers.ToList();
List<Room> masterList = new();
ClearAllServersLists();
List<Room> requestedRooms;

for(int i = 0; i < relays.Count; i++)
for (int i = 0; i < relays.Count; i++)
{
masterList.AddRange(await Program.instance.RequestServerListFromNode(relays[i].Key.Address, relays[i].Key.EndpointPort));
requestedRooms = await Program.instance.RequestServerListFromNode(relays[i].Key.address, relays[i].Key.endpointPort);
allServers.AddRange(requestedRooms);

switch (relays[i].Key.serverRegion)
{
case (LRMRegions.NorthAmerica):
northAmericaServers.AddRange(requestedRooms);
break;
case (LRMRegions.SouthAmerica):
southAmericaServers.AddRange(requestedRooms);
break;
case (LRMRegions.Europe):
europeServers.AddRange(requestedRooms);
break;
case (LRMRegions.Africa):
africaServers.AddRange(requestedRooms);
break;
case (LRMRegions.Asia):
asiaServers.AddRange(requestedRooms);
break;
case (LRMRegions.Oceania):
oceaniaServers.AddRange(requestedRooms);
break;
}
}

cachedServerList = JsonConvert.SerializeObject(masterList);
CacheAllServers();
}
}

void CacheAllServers()
{
allCachedServers = JsonConvert.SerializeObject(allServers);
NorthAmericaCachedServers = JsonConvert.SerializeObject(northAmericaServers);
SouthAmericaCachedServers = JsonConvert.SerializeObject(southAmericaServers);
EuropeCachedServers = JsonConvert.SerializeObject(europeServers);
AsiaCachedServers = JsonConvert.SerializeObject(asiaServers);
AfricaCachedServers = JsonConvert.SerializeObject(africaServers);
OceaniaCachedServers = JsonConvert.SerializeObject(oceaniaServers);
}

void ClearAllServersLists()
{
northAmericaServers.Clear();
southAmericaServers.Clear();
europeServers.Clear();
asiaServers.Clear();
africaServers.Clear();
oceaniaServers.Clear();
allServers.Clear();
}

/// <summary>
/// Hooks into from unity side, client will call this to
/// find the least populated server to join
Expand All @@ -119,15 +181,15 @@ public async Task JoinRelay(IHttpContext context)

for (int i = 0; i < servers.Count; i++)
{
if (servers[i].Value.ConnectedClients < lowest.Value.ConnectedClients)
if (servers[i].Value.connectedClients < lowest.Value.connectedClients)
{
lowest = servers[i];
}
}

// respond with the server ip
// if the string is still dummy then theres no servers
if (lowest.Key.Address != "Dummy")
if (lowest.Key.address != "Dummy")
{
await context.Response.SendResponseAsync(JsonConvert.SerializeObject(lowest.Key));
}
Expand All @@ -145,7 +207,40 @@ public async Task JoinRelay(IHttpContext context)
[RestRoute("Get", "/api/masterlist/")]
public async Task GetMasterServerList(IHttpContext context)
{
await context.Response.SendResponseAsync(cachedServerList);
string region = context.Request.Headers["x-Region"];

if(int.TryParse(region, out int regionID))
{
switch ((LRMRegions)regionID)
{
case LRMRegions.Any:
await context.Response.SendResponseAsync(allCachedServers);
break;
case LRMRegions.NorthAmerica:
await context.Response.SendResponseAsync(NorthAmericaCachedServers);
break;
case LRMRegions.SouthAmerica:
await context.Response.SendResponseAsync(SouthAmericaCachedServers);
break;
case LRMRegions.Europe:
await context.Response.SendResponseAsync(EuropeCachedServers);
break;
case LRMRegions.Africa:
await context.Response.SendResponseAsync(AfricaCachedServers);
break;
case LRMRegions.Asia:
await context.Response.SendResponseAsync(AsiaCachedServers);
break;
case LRMRegions.Oceania:
await context.Response.SendResponseAsync(OceaniaCachedServers);
break;
}

return;
}

// They didnt submit a region header, just give them all servers as they probably are viewing in browser.
await context.Response.SendResponseAsync(allCachedServers);
}

/// <summary>
Expand Down Expand Up @@ -218,7 +313,7 @@ private static List<string> GetLocalIps()

bool hasLocal = false;

for(int i = 0; i < bindableIPv4Addresses.Count; i++)
for (int i = 0; i < bindableIPv4Addresses.Count; i++)
{
if (bindableIPv4Addresses[i] == "127.0.0.1")
hasLocal = true;
Expand All @@ -233,4 +328,4 @@ private static List<string> GetLocalIps()

}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ public async Task MainAsync()
/// <param name="endpointPort"></param>
/// <param name="publicIP"></param>
/// <returns></returns>
public async Task AddServer(string serverIP, ushort port, ushort endpointPort, string publicIP)
public async Task AddServer(string serverIP, ushort port, ushort endpointPort, string publicIP, int regionId)
{
var relayAddr = new RelayAddress { Port = port, EndpointPort = endpointPort, Address = publicIP, EndpointAddress = serverIP };
var relayAddr = new RelayAddress { port = port, endpointPort = endpointPort, address = publicIP, endpointAddress = serverIP.Trim(), serverRegion = (LRMRegions)regionId };

if (availableRelayServers.ContainsKey(relayAddr))
{
Expand Down Expand Up @@ -187,13 +187,14 @@ async void PingServers()

for (int i = 0; i < keys.Count; i++)
{
if(!await HealthCheckNode(keys[i].EndpointAddress, keys[i].EndpointPort))
if(!await HealthCheckNode(keys[i].endpointAddress, keys[i].endpointPort))
{
Logger.ForceLogMessage($"Server {keys[i].Address}:{keys[i].Port} failed a health check, removing from load balancer.", ConsoleColor.Red);
Logger.ForceLogMessage($"Server {keys[i].address}:{keys[i].port} failed a health check, removing from load balancer.", ConsoleColor.Red);
availableRelayServers.Remove(keys[i]);
}
}

GC.Collect();
await Task.Delay(_pingDelay);
}
}
Expand Down Expand Up @@ -229,5 +230,4 @@ ____ _ _ _ _____ ______ _____
Logger.ForceLogMessage(load, ConsoleColor.Cyan);
}
}

}
1 change: 1 addition & 0 deletions ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ class Config
public string LoadBalancerAuthKey = "AuthKey";
public string LoadBalancerAddress = "127.0.0.1";
public ushort LoadBalancerPort = 7070;
public LRMRegions LoadBalancerRegion = LRMRegions.NorthAmerica;
}
}
15 changes: 15 additions & 0 deletions ServerProject-DONT-IMPORT-INTO-UNITY/LRM/LRM.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,19 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

</Project>
3 changes: 2 additions & 1 deletion ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,14 @@ private async Task<bool> RegisterSelfToLoadBalancer()

var uri = new Uri($"http://{conf.LoadBalancerAddress}:{conf.LoadBalancerPort}/api/auth");
string endpointPort = conf.EndpointPort.ToString();
string gamePort = 7777.ToString();
string gamePort = "7777";
HttpWebRequest authReq = (HttpWebRequest)WebRequest.Create(uri);

authReq.Headers.Add("Authorization", conf.LoadBalancerAuthKey);
authReq.Headers.Add("x-EndpointPort", endpointPort);
authReq.Headers.Add("x-GamePort", gamePort);
authReq.Headers.Add("x-PIP", publicIP); // Public IP
authReq.Headers.Add("x-Region", ((int)conf.LoadBalancerRegion).ToString());

var res = await authReq.GetResponseAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ partial class Program

private readonly string CONFIG_PATH = System.Environment.GetEnvironmentVariable("LRM_CONFIG_PATH") ?? "config.json";
}

public enum LRMRegions { Any, NorthAmerica, SouthAmerica, Europe, Asia, Africa, Oceania }
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,10 @@ void CreateRoom(int clientId, int maxPlayers, string serverName, bool isPublic,
serverData = serverData,
clients = new List<int>(),

// hard coded for now REMEMBER TO UN-HARDCODE RETARD
// hard coded for now REMEMBER TO UN-HARDCODE
// 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 },
relayInfo = new RelayAddress { address = Program.publicIP, port = 7777, endpointPort = Program.conf.EndpointPort },

serverId = GetRandomServerID(),
hostIP = hostIP,
Expand Down
6 changes: 3 additions & 3 deletions ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Room.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public class Room
[Serializable]
public struct RelayAddress
{
public ushort Port;
public ushort EndpointPort;
public string Address;
public ushort port;
public ushort endpointPort;
public string address;
}
}
Loading

0 comments on commit 14ea624

Please sign in to comment.