1
0
mirror of https://github.com/ncblakely/GiantsTools synced 2024-11-23 06:35:37 +01:00

Fix various issues with multiple servers from a single IP.

This commit is contained in:
Nick Blakely 2020-11-14 18:49:29 -08:00
parent eb33ce0bb7
commit e6747b0d3a
4 changed files with 36 additions and 28 deletions

View File

@ -4,7 +4,7 @@
public class ServerInfo : DataContract.V1.ServerInfo, IIdentifiable public class ServerInfo : DataContract.V1.ServerInfo, IIdentifiable
{ {
public string id => this.HostIpAddress; public string id => $"{this.HostIpAddress}-{this.GameName}-{this.Port}";
public string DocumentType => nameof(ServerInfo); public string DocumentType => nameof(ServerInfo);
@ -17,6 +17,8 @@
return obj is ServerInfo info && return obj is ServerInfo info &&
base.Equals(obj) && base.Equals(obj) &&
this.HostIpAddress == info.HostIpAddress && this.HostIpAddress == info.HostIpAddress &&
this.Port == info.Port &&
this.GameName == info.GameName &&
this.DocumentType == info.DocumentType; this.DocumentType == info.DocumentType;
} }

View File

@ -10,12 +10,12 @@
public class ServerRegistryService : IServerRegistryService public class ServerRegistryService : IServerRegistryService
{ {
private static readonly string[] SupportedGameNames = new[] { "Giants", "Giants Beta" }; private static readonly string[] SupportedGameNames = new[] { "Giants", "Giants Beta", "Giants Beta Dedicated", "Giants Dedicated" };
private readonly ILogger<ServerRegistryService> logger; private readonly ILogger<ServerRegistryService> logger;
private readonly IServerRegistryStore registryStore; private readonly IServerRegistryStore registryStore;
private readonly IConfiguration configuration; private readonly IConfiguration configuration;
private readonly int maxServerCount; private readonly int maxServerCount;
private readonly int maxServersPerIpGame; private readonly int maxServersPerIp;
public ServerRegistryService( public ServerRegistryService(
ILogger<ServerRegistryService> logger, ILogger<ServerRegistryService> logger,
@ -26,7 +26,7 @@
this.registryStore = registryStore; this.registryStore = registryStore;
this.configuration = configuration; this.configuration = configuration;
this.maxServerCount = Convert.ToInt32(this.configuration["MaxServerCount"]); this.maxServerCount = Convert.ToInt32(this.configuration["MaxServerCount"]);
this.maxServersPerIpGame = Convert.ToInt32(this.configuration["MaxServersPerIpGame"]); this.maxServersPerIp = Convert.ToInt32(this.configuration["MaxServersPerIp"]);
} }
public async Task AddServer( public async Task AddServer(
@ -35,13 +35,15 @@
ArgumentUtility.CheckForNull(serverInfo, nameof(serverInfo)); ArgumentUtility.CheckForNull(serverInfo, nameof(serverInfo));
ArgumentUtility.CheckStringForNullOrEmpty(serverInfo.HostIpAddress, nameof(serverInfo.HostIpAddress)); ArgumentUtility.CheckStringForNullOrEmpty(serverInfo.HostIpAddress, nameof(serverInfo.HostIpAddress));
string gameName = serverInfo.GameName.Replace("Dedicated", string.Empty).Trim();
serverInfo.GameName = gameName;
if (!SupportedGameNames.Contains(serverInfo.GameName, StringComparer.OrdinalIgnoreCase)) if (!SupportedGameNames.Contains(serverInfo.GameName, StringComparer.OrdinalIgnoreCase))
{ {
throw new ArgumentException($"Unsupported game name {serverInfo.GameName}", nameof(serverInfo)); throw new ArgumentException($"Unsupported game name {serverInfo.GameName}", nameof(serverInfo));
} }
var existingServers = await this.registryStore.GetServerInfos(whereExpression: x => x.HostIpAddress == serverInfo.HostIpAddress); var existingServers = await this.registryStore.GetServerInfos(whereExpression: x => x.HostIpAddress == serverInfo.HostIpAddress);
if (existingServers.GroupBy(g => g.GameName).Any(g => g.Count() > this.maxServersPerIpGame)) if (existingServers.GroupBy(g => new { g.HostIpAddress }).Any(g => g.Count() > this.maxServersPerIp))
{ {
throw new InvalidOperationException("Exceeded maximum servers per IP."); throw new InvalidOperationException("Exceeded maximum servers per IP.");
} }

View File

@ -99,7 +99,8 @@
if (allServerInfo.ContainsKey(serverInfo.HostIpAddress)) if (allServerInfo.ContainsKey(serverInfo.HostIpAddress))
{ {
ServerInfo existingServerInfo = FindExistingServerForHostIp(allServerInfo[serverInfo.HostIpAddress], serverInfo); IList<ServerInfo> serverInfoForHostIp = allServerInfo[serverInfo.HostIpAddress];
ServerInfo existingServerInfo = FindExistingServerForHostIp(serverInfoForHostIp, serverInfo);
// DDOS protection: skip write to Cosmos if parameters have not changed, // DDOS protection: skip write to Cosmos if parameters have not changed,
// or it's not been long enough. // or it's not been long enough.
@ -108,24 +109,35 @@
this.logger.LogInformation("State for {IPAddress} is unchanged. Skipping write to store.", serverInfo.HostIpAddress); this.logger.LogInformation("State for {IPAddress} is unchanged. Skipping write to store.", serverInfo.HostIpAddress);
return; return;
} }
else
{
this.logger.LogInformation("State for {IPAddress} has changed. Committing update to store.", serverInfo.HostIpAddress);
}
}
this.logger.LogInformation("State for {IPAddress} has changed. Committing update to store.", serverInfo.HostIpAddress);
await this.client.UpsertItem( await this.client.UpsertItem(
item: serverInfo, item: serverInfo,
partitionKey: new PartitionKey(serverInfo.DocumentType)); partitionKey: new PartitionKey(serverInfo.DocumentType));
this.logger.LogInformation("Updating cache for request from {IPAddress}.", serverInfo.HostIpAddress); // Update cache
if (existingServerInfo != null)
if (allServerInfo.ContainsKey(serverInfo.HostIpAddress))
{ {
allServerInfo[serverInfo.HostIpAddress].Add(serverInfo); var newServerInfo = serverInfoForHostIp.Where(s => !s.Equals(serverInfo)).ToList();
newServerInfo.Add(serverInfo);
allServerInfo[serverInfo.HostIpAddress] = newServerInfo;
this.logger.LogInformation("Updating cache for request from {IPAddress} (replaced existing server).", serverInfo.HostIpAddress);
} }
else else
{ {
allServerInfo[serverInfo.HostIpAddress].Add(serverInfo);
this.logger.LogInformation("Updating cache for request from {IPAddress} (added new server).", serverInfo.HostIpAddress);
}
}
else
{
// Update cache
await this.client.UpsertItem(
item: serverInfo,
partitionKey: new PartitionKey(serverInfo.DocumentType));
this.logger.LogInformation("Updating cache for request from {IPAddress} (no existing servers).", serverInfo.HostIpAddress);
allServerInfo.TryAdd(serverInfo.HostIpAddress, new List<ServerInfo>() { serverInfo }); allServerInfo.TryAdd(serverInfo.HostIpAddress, new List<ServerInfo>() { serverInfo });
} }
} }
@ -199,15 +211,7 @@
private static ServerInfo FindExistingServerForHostIp(IList<ServerInfo> serverInfoForHostIp, ServerInfo candidateServerInfo) private static ServerInfo FindExistingServerForHostIp(IList<ServerInfo> serverInfoForHostIp, ServerInfo candidateServerInfo)
{ {
foreach (var existingServerInfo in serverInfoForHostIp) return serverInfoForHostIp.FirstOrDefault(s => s.Equals(candidateServerInfo));
{
if (existingServerInfo.Equals(candidateServerInfo))
{
return existingServerInfo;
}
}
return null;
} }
} }
} }

View File

@ -12,7 +12,7 @@
"ServerTimeoutPeriodInMinutes": "7", "ServerTimeoutPeriodInMinutes": "7",
"ServerCleanupIntervalInMinutes": "1", "ServerCleanupIntervalInMinutes": "1",
"MaxServerCount": 1000, "MaxServerCount": 1000,
"MaxServersPerIpGame": 5, "MaxServersPerIp": 5,
"DiscordUri": "https://discord.gg/Avj4azU", "DiscordUri": "https://discord.gg/Avj4azU",
"BlobConnectionString": "", "BlobConnectionString": "",
"CrashBlobContainerName": "crashes" "CrashBlobContainerName": "crashes"