internal class GameManager
{
private readonly ILogger<GameManager> _logger;
- private readonly INodeProvider _nodeProvider;
+ private readonly INodeLocator _nodeLocator;
private readonly IPEndPoint _publicIp;
private readonly ConcurrentDictionary<int, Game> _games;
- public GameManager(ILogger<GameManager> logger, IOptions<ServerConfig> config, INodeProvider nodeProvider)
+ public GameManager(ILogger<GameManager> logger, IOptions<ServerConfig> config, INodeLocator nodeLocator)
{
_logger = logger;
- _nodeProvider = nodeProvider;
+ _nodeLocator = nodeLocator;
_publicIp = new IPEndPoint(IPAddress.Parse(config.Value.PublicIp), config.Value.PublicPort);
_games = new ConcurrentDictionary<int, Game>();
}
var gameCode = GameCode.GenerateCode(6);
var gameCodeStr = GameCode.IntToGameName(gameCode);
- var game = new Game(this, _nodeProvider, _publicIp, gameCode, options);
+ var game = new Game(this, _nodeLocator, _publicIp, gameCode, options);
- if (_nodeProvider.Find(gameCodeStr) == null &&
+ if (_nodeLocator.Find(gameCodeStr) == null &&
_games.TryAdd(gameCode, game))
{
- _nodeProvider.Save(gameCodeStr, _publicIp);
+ _nodeLocator.Save(gameCodeStr, _publicIp);
_logger.LogDebug("Created game with code {0} ({1}).", game.CodeStr, gameCode);
return game;
}
public void Remove(int gameCode)
{
_logger.LogDebug("Remove game with code {0} ({1}).", GameCode.IntToGameName(gameCode), gameCode);
- _nodeProvider.Remove(GameCode.IntToGameName(gameCode));
+ _nodeLocator.Remove(GameCode.IntToGameName(gameCode));
_games.TryRemove(gameCode, out _);
}
}
{
private readonly ILogger<ClientManagerRedirector> _logger;
private readonly INodeProvider _nodeProvider;
+ private readonly INodeLocator _nodeLocator;
private readonly HashSet<ClientRedirector> _clients;
- public ClientManagerRedirector(ILogger<ClientManagerRedirector> logger, INodeProvider nodeProvider)
+ public ClientManagerRedirector(ILogger<ClientManagerRedirector> logger, INodeProvider nodeProvider, INodeLocator nodeLocator)
{
_logger = logger;
_nodeProvider = nodeProvider;
+ _nodeLocator = nodeLocator;
_clients = new HashSet<ClientRedirector>();
}
public void Create(string name, Connection connection)
{
_logger.LogInformation("Client connected.");
- _clients.Add(new ClientRedirector(name, connection, this, _nodeProvider));
+ _clients.Add(new ClientRedirector(name, connection, this, _nodeProvider, _nodeLocator));
}
public void Remove(ClientRedirector client)
private readonly Connection _connection;
private readonly ClientManagerRedirector _clientManager;
private readonly INodeProvider _nodeProvider;
+ private readonly INodeLocator _nodeLocator;
- public ClientRedirector(string name, Connection connection, ClientManagerRedirector clientManager, INodeProvider nodeProvider)
+ public ClientRedirector(string name, Connection connection, ClientManagerRedirector clientManager, INodeProvider nodeProvider, INodeLocator nodeLocator)
{
_name = name;
_connection = connection;
_connection.Disconnected += OnDisconnected;
_clientManager = clientManager;
_nodeProvider = nodeProvider;
+ _nodeLocator = nodeLocator;
}
private void OnDataReceived(DataReceivedEventArgs e)
using (var packet = MessageWriter.Get(SendOption.Reliable))
{
- var endpoint = _nodeProvider.Find(GameCode.IntToGameName(gameCode));
+ var endpoint = _nodeLocator.Find(GameCode.IntToGameName(gameCode));
if (endpoint == null)
{
Message01JoinGame.SerializeError(packet, false, DisconnectReason.GameMissing);
--- /dev/null
+using System.Net;
+
+namespace Impostor.Server.Net.Redirector
+{
+ public interface INodeLocator
+ {
+ IPEndPoint Find(string gameCode);
+ void Save(string gameCode, IPEndPoint endPoint);
+ void Remove(string gameCode);
+ }
+}
\ No newline at end of file
internal interface INodeProvider
{
IPEndPoint Get();
- IPEndPoint Find(string gameCode);
- void Save(string gameCode, IPEndPoint endPoint);
- void Remove(string gameCode);
}
}
\ No newline at end of file
--- /dev/null
+using System.Net;
+
+namespace Impostor.Server.Net.Redirector
+{
+ public class NodeLocatorNoOp : INodeLocator
+ {
+ public IPEndPoint Find(string gameCode)
+ {
+ // Do nothing.
+ return null;
+ }
+
+ public void Save(string gameCode, IPEndPoint endPoint)
+ {
+ // Do nothing.
+ }
+
+ public void Remove(string gameCode)
+ {
+ // Do nothing.
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Net;
+using Microsoft.Extensions.Caching.Distributed;
+
+namespace Impostor.Server.Net.Redirector
+{
+ public class NodeLocatorRedis : INodeLocator
+ {
+ private readonly IDistributedCache _cache;
+
+ public NodeLocatorRedis(IDistributedCache cache)
+ {
+ _cache = cache;
+ }
+
+ public IPEndPoint Find(string gameCode)
+ {
+ var entry = _cache.GetString(gameCode);
+ if (entry == null)
+ {
+ return null;
+ }
+
+ return IPEndPoint.Parse(entry);
+ }
+
+ public void Save(string gameCode, IPEndPoint endPoint)
+ {
+ _cache.SetString(gameCode, endPoint.ToString(), new DistributedCacheEntryOptions
+ {
+ SlidingExpiration = TimeSpan.FromHours(1)
+ });
+ }
+
+ public void Remove(string gameCode)
+ {
+ _cache.Remove(gameCode);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Net;
+using Impostor.Server.Data;
+using Microsoft.Extensions.Options;
+
+namespace Impostor.Server.Net.Redirector
+{
+ internal class NodeProviderConfig : INodeProvider
+ {
+ private readonly List<IPEndPoint> _nodes;
+ private readonly object _lock;
+ private int _currentIndex;
+
+ public NodeProviderConfig(IOptions<ServerRedirectorConfig> redirectorConfig)
+ {
+ _nodes = new List<IPEndPoint>();
+ _lock = new object();
+
+ if (redirectorConfig.Value.Nodes != null)
+ {
+ foreach (var node in redirectorConfig.Value.Nodes)
+ {
+ _nodes.Add(new IPEndPoint(IPAddress.Parse(node.Ip), node.Port));
+ }
+ }
+ }
+
+ public IPEndPoint Get()
+ {
+ lock (_lock)
+ {
+ var node = _nodes[_currentIndex++];
+
+ if (_currentIndex == _nodes.Count)
+ {
+ _currentIndex = 0;
+ }
+
+ return node;
+ }
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Net;
-
-namespace Impostor.Server.Net.Redirector
-{
- public class NodeProviderNoOp : INodeProvider
- {
- public IPEndPoint Get()
- {
- throw new NotImplementedException();
- }
-
- public IPEndPoint Find(string gameCode)
- {
- // Do nothing.
- return null;
- }
-
- public void Save(string gameCode, IPEndPoint endPoint)
- {
- // Do nothing.
- }
-
- public void Remove(string gameCode)
- {
- // Do nothing.
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using System.Net;
-using Impostor.Server.Data;
-using Microsoft.Extensions.Caching.Distributed;
-using Microsoft.Extensions.Options;
-
-namespace Impostor.Server.Net.Redirector
-{
- internal class NodeProviderRedis : INodeProvider
- {
- private readonly IDistributedCache _cache;
- private readonly List<IPEndPoint> _nodes;
- private readonly object _lock;
- private int _currentIndex;
-
- public NodeProviderRedis(IOptions<ServerRedirectorConfig> redirectorConfig, IDistributedCache cache)
- {
- _cache = cache;
- _nodes = new List<IPEndPoint>();
- _lock = new object();
-
- if (redirectorConfig.Value.Nodes != null)
- {
- foreach (var node in redirectorConfig.Value.Nodes)
- {
- _nodes.Add(new IPEndPoint(IPAddress.Parse(node.Ip), node.Port));
- }
- }
- }
-
- public IPEndPoint Get()
- {
- lock (_lock)
- {
- var node = _nodes[_currentIndex++];
-
- if (_currentIndex == _nodes.Count)
- {
- _currentIndex = 0;
- }
-
- return node;
- }
- }
-
- public IPEndPoint Find(string gameCode)
- {
- var entry = _cache.GetString(gameCode);
- if (entry == null)
- {
- return null;
- }
-
- return IPEndPoint.Parse(entry);
- }
-
- public void Save(string gameCode, IPEndPoint endPoint)
- {
- _cache.SetString(gameCode, endPoint.ToString(), new DistributedCacheEntryOptions
- {
- SlidingExpiration = TimeSpan.FromHours(1)
- });
- }
-
- public void Remove(string gameCode)
- {
- _cache.Remove(gameCode);
- }
- }
-}
\ No newline at end of file
private static readonly ILogger Logger = Log.ForContext<Game>();
private readonly GameManager _gameManager;
- private readonly INodeProvider _nodeProvider;
+ private readonly INodeLocator _nodeLocator;
private readonly ConcurrentDictionary<int, ClientPlayer> _players;
private readonly HashSet<IPAddress> _bannedIps;
- public Game(GameManager gameManager, INodeProvider nodeProvider, IPEndPoint publicIp, int code, GameOptionsData options)
+ public Game(GameManager gameManager, INodeLocator nodeLocator, IPEndPoint publicIp, int code, GameOptionsData options)
{
_gameManager = gameManager;
- _nodeProvider = nodeProvider;
+ _nodeLocator = nodeLocator;
_players = new ConcurrentDictionary<int, ClientPlayer>();
_bannedIps = new HashSet<IPAddress>();
if (redirector.Enabled)
{
- services.AddSingleton<INodeProvider, NodeProviderRedis>();
+ // When joining a game, it retrieves the game server ip from redis.
+ // When a game has been created on this node, it stores the game code with its ip in redis.
+ services.AddSingleton<INodeLocator, NodeLocatorRedis>();
+
+ // Use the configuration as source for the list of nodes to provide
+ // when creating a game.
+ services.AddSingleton<INodeProvider, NodeProviderConfig>();
+
+ // Dependency for the NodeLocatorRedis.
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = redirector.Redis;
}
else
{
- services.AddSingleton<INodeProvider, NodeProviderNoOp>();
+ // Redirector is not enabled but the dependency is still required.
+ // So we provide one that ignores all calls.
+ services.AddSingleton<INodeLocator, NodeLocatorNoOp>();
}
if (redirector.Enabled && redirector.Master)
{
services.AddSingleton<IClientManager, ClientManagerRedirector>();
+ // For a master server, we don't need a GameManager.
}
else
{
{
"Ip": "127.0.0.1",
"Port": 22024
- },
- {
- "Ip": "127.0.0.1",
- "Port": 22025
}
]
}