From: AeonLucid Date: Sat, 26 Sep 2020 03:43:37 +0000 (+0200) Subject: Added server redirection using redis X-Git-Tag: v1.1.0~1^2~40 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=f2a23d5bbb0099496dda494769be5817f8c6e1da;p=rhonda%2Fimpostor.git Added server redirection using redis --- diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e9a690c..e4720ac 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -19,7 +19,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 3.1.301 + dotnet-version: 3.1.402 - name: Install dependencies run: dotnet restore ./src - name: Build Impostor.Client diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d51ecae..8d14e71 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,7 +26,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 3.1.301 + dotnet-version: 3.1.402 - name: Install dependencies run: dotnet restore ./src - name: Build Impostor.Client @@ -35,13 +35,3 @@ jobs: run: dotnet build --no-restore -c Release -f netcoreapp3.1 ./src/Impostor.Server/Impostor.Server.csproj /p:PublishTrimmed=false - name: Test run: dotnet test --no-restore -v normal -f netcoreapp3.1 ./src - deploy: - name: Deploy - runs-on: windows-latest - needs: build - if: github.event_name == 'release' - steps: - - name: Publish Impostor.Server (win-x64) - run: dotnet publish -c release -o /build/linux-x64 -f netcoreapp3.1 -r win-x64 --self-contained --no-restore ./src/Impostor.Server/Impostor.Server.csproj - - name: Publish Impostor.Server (linux-x64) - run: dotnet publish -c release -o /build/linux-x64 -f netcoreapp3.1 -r linux-x64 --self-contained --no-restore ./src/Impostor.Server/Impostor.Server.csproj \ No newline at end of file diff --git a/src/.gitignore b/src/.gitignore index 3c4efe2..e0838ba 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,5 @@ +config.*.json + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. diff --git a/src/Impostor.Server/Data/DisconnectMessages.cs b/src/Impostor.Server/Data/DisconnectMessages.cs index 1c16173..50dc00f 100644 --- a/src/Impostor.Server/Data/DisconnectMessages.cs +++ b/src/Impostor.Server/Data/DisconnectMessages.cs @@ -8,5 +8,8 @@ public const string Destroyed = "The game you tried to join is being destroyed. " + "Please create a new game."; + + public const string NotImplemented = "Game listing has not been implemented in Impostor yet for servers " + + "running in server redirection mode."; } } \ No newline at end of file diff --git a/src/Impostor.Server/Data/ServerConfig.cs b/src/Impostor.Server/Data/ServerConfig.cs index 007b5ed..5bcf68d 100644 --- a/src/Impostor.Server/Data/ServerConfig.cs +++ b/src/Impostor.Server/Data/ServerConfig.cs @@ -1,7 +1,9 @@ namespace Impostor.Server.Data { - public class ServerConfig + internal class ServerConfig { + public const string Section = "Server"; + public string PublicIp { get; set; } = "127.0.0.1"; public ushort PublicPort { get; set; } = 22023; public string ListenIp { get; set; } = "127.0.0.1"; diff --git a/src/Impostor.Server/Data/ServerRedirectorConfig.cs b/src/Impostor.Server/Data/ServerRedirectorConfig.cs new file mode 100644 index 0000000..cd5b4d7 --- /dev/null +++ b/src/Impostor.Server/Data/ServerRedirectorConfig.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Impostor.Server.Data +{ + internal class ServerRedirectorConfig + { + public const string Section = "ServerRedirector"; + + public bool Enabled { get; set; } + public bool Master { get; set; } + public string Redis { get; set; } + public List Nodes { get; set; } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Data/ServerRedirectorNode.cs b/src/Impostor.Server/Data/ServerRedirectorNode.cs new file mode 100644 index 0000000..8da03ad --- /dev/null +++ b/src/Impostor.Server/Data/ServerRedirectorNode.cs @@ -0,0 +1,8 @@ +namespace Impostor.Server.Data +{ + internal class ServerRedirectorNode + { + public string Ip { get; set; } + public ushort Port { get; set; } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Impostor.Server.csproj b/src/Impostor.Server/Impostor.Server.csproj index 003e636..0387f84 100644 --- a/src/Impostor.Server/Impostor.Server.csproj +++ b/src/Impostor.Server/Impostor.Server.csproj @@ -18,6 +18,7 @@ + @@ -27,6 +28,9 @@ PreserveNewest + + PreserveNewest + diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index f171a74..f949134 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -1,4 +1,4 @@ -using System; +using System; using Hazel; using Impostor.Server.Data; using Impostor.Server.Net.Manager; @@ -10,7 +10,7 @@ using ILogger = Serilog.ILogger; namespace Impostor.Server.Net { - public class Client + internal class Client { private static readonly ILogger Logger = Log.ForContext(); diff --git a/src/Impostor.Server/Net/Manager/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs index b4f7684..28298c5 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -1,26 +1,29 @@ using System.Collections.Concurrent; +using Hazel; using Impostor.Server.Exceptions; -using Serilog; +using Microsoft.Extensions.Logging; namespace Impostor.Server.Net.Manager { - public class ClientManager + internal class ClientManager : IClientManager { - private static readonly ILogger Logger = Log.ForContext(); - + private readonly ILogger _clientManager; + private readonly GameManager _gameManager; private readonly ConcurrentDictionary _clients; private readonly object _idLock; private int _idLast; - public ClientManager() + public ClientManager(ILogger clientManager, GameManager gameManager) { + _clientManager = clientManager; + _gameManager = gameManager; _clients = new ConcurrentDictionary(); _idLock = new object(); _idLast = 0; } // No idea what a good way for this is. - public int NextId() + private int NextId() { lock (_idLock) { @@ -35,7 +38,7 @@ namespace Impostor.Server.Net.Manager _idLast = 0; } - if (_clients.ContainsKey(_idLast)) + if (_clients.ContainsKey(result)) { continue; } @@ -47,17 +50,17 @@ namespace Impostor.Server.Net.Manager } } - public void Add(Client client) + public void Create(string name, Connection connection) { - Logger.Information("Client connected."); - - _clients.TryAdd(client.Id, client); + var clientId = NextId(); + + _clientManager.LogInformation("Client connected."); + _clients.TryAdd(clientId, new Client(this, _gameManager, clientId, name, connection)); } public void Remove(Client client) { - Logger.Information("Client disconnected."); - + _clientManager.LogInformation("Client disconnected."); _clients.TryRemove(client.Id, out _); } } diff --git a/src/Impostor.Server/Net/Manager/GameManager.cs b/src/Impostor.Server/Net/Manager/GameManager.cs index 291b9d2..7c0db53 100644 --- a/src/Impostor.Server/Net/Manager/GameManager.cs +++ b/src/Impostor.Server/Net/Manager/GameManager.cs @@ -1,8 +1,9 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using Impostor.Server.Data; +using Impostor.Server.Net.Redirector; using Impostor.Server.Net.State; using Impostor.Shared.Innersloth; using Impostor.Shared.Innersloth.Data; @@ -11,26 +12,33 @@ using Microsoft.Extensions.Options; namespace Impostor.Server.Net.Manager { - public class GameManager + internal class GameManager { private readonly ILogger _logger; + private readonly INodeProvider _nodeProvider; private readonly IPEndPoint _publicIp; private readonly ConcurrentDictionary _games; - public GameManager(ILogger logger, IOptions config) + public GameManager(ILogger logger, IOptions config, INodeProvider nodeProvider) { _logger = logger; + _nodeProvider = nodeProvider; _publicIp = new IPEndPoint(IPAddress.Parse(config.Value.PublicIp), config.Value.PublicPort); _games = new ConcurrentDictionary(); } public Game Create(GameOptionsData options) { + // TODO: Prevent duplicates when using server redirector using INodeProvider. + var gameCode = GameCode.GenerateCode(6); - var game = new Game(this, _publicIp, gameCode, options); + var gameCodeStr = GameCode.IntToGameName(gameCode); + var game = new Game(this, _nodeProvider, _publicIp, gameCode, options); - if (_games.TryAdd(gameCode, game)) + if (_nodeProvider.Find(gameCodeStr) == null && + _games.TryAdd(gameCode, game)) { + _nodeProvider.Save(gameCodeStr, _publicIp); _logger.LogDebug("Created game with code {0} ({1}).", game.CodeStr, gameCode); return game; } @@ -53,7 +61,7 @@ namespace Impostor.Server.Net.Manager foreach (var (code, game) in _games.Where(x => x.Value.IsPublic && x.Value.GameState == GameStates.NotStarted && - x.Value.PlayerCount < 10)) + x.Value.PlayerCount < 10)) // TODO: Do "< x.Value.Options.MaxPlayers" when GameData packets are done. { // Check for options. // TODO: Re-enable map filter when GameData packets are done. @@ -77,7 +85,8 @@ namespace Impostor.Server.Net.Manager public void Remove(int gameCode) { - _logger.LogDebug("Remove game with code {0} ({1}).", GameCode.IntToGameName(gameCode), gameCode); + _logger.LogDebug("Remove game with code {0} ({1}).", GameCode.IntToGameName(gameCode), gameCode); + _nodeProvider.Remove(GameCode.IntToGameName(gameCode)); _games.TryRemove(gameCode, out _); } } diff --git a/src/Impostor.Server/Net/Manager/IClientManager.cs b/src/Impostor.Server/Net/Manager/IClientManager.cs new file mode 100644 index 0000000..4449e2d --- /dev/null +++ b/src/Impostor.Server/Net/Manager/IClientManager.cs @@ -0,0 +1,9 @@ +using Hazel; + +namespace Impostor.Server.Net.Manager +{ + internal interface IClientManager + { + void Create(string name, Connection connection); + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index b7bdb32..46759e5 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -10,21 +10,22 @@ using Microsoft.Extensions.Options; namespace Impostor.Server.Net { - public class Matchmaker + internal class Matchmaker { private readonly ILogger _logger; - private readonly ServerConfig _config; - private readonly GameManager _gameManager; - private readonly ClientManager _clientManager; + private readonly ServerConfig _serverConfig; + private readonly IClientManager _clientManager; private readonly UdpConnectionListener _connection; - public Matchmaker(ILogger logger, IOptions configOptions, GameManager gameManager) + public Matchmaker( + ILogger logger, + IOptions serverConfig, + IClientManager clientManager) { _logger = logger; - _config = configOptions.Value; - _gameManager = gameManager; - _clientManager = new ClientManager(); - _connection = new UdpConnectionListener(new IPEndPoint(IPAddress.Parse(_config.ListenIp), _config.ListenPort), IPMode.IPv4, s => + _serverConfig = serverConfig.Value; + _clientManager = clientManager; + _connection = new UdpConnectionListener(new IPEndPoint(IPAddress.Parse(_serverConfig.ListenIp), _serverConfig.ListenPort), IPMode.IPv4, s => { _logger.LogWarning("Log from Hazel: {0}", s); }); @@ -52,8 +53,8 @@ namespace Impostor.Server.Net return; } - // Register client. - _clientManager.Add(new Client(_clientManager, _gameManager, _clientManager.NextId(), clientName, e.Connection)); + // Create client. + _clientManager.Create(clientName, e.Connection); } public void Start() diff --git a/src/Impostor.Server/Net/MatchmakerService.cs b/src/Impostor.Server/Net/MatchmakerService.cs index 43fe21e..08d0f1e 100644 --- a/src/Impostor.Server/Net/MatchmakerService.cs +++ b/src/Impostor.Server/Net/MatchmakerService.cs @@ -1,27 +1,47 @@ using System.Threading; using System.Threading.Tasks; +using Impostor.Server.Data; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace Impostor.Server.Net { - public class MatchmakerService : IHostedService + internal class MatchmakerService : IHostedService { private readonly ILogger _logger; + private readonly ServerConfig _serverConfig; + private readonly ServerRedirectorConfig _redirectorConfig; private readonly Matchmaker _matchmaker; - public MatchmakerService(ILogger logger, Matchmaker matchmaker) + public MatchmakerService( + ILogger logger, + IOptions serverConfig, + IOptions redirectorConfig, + Matchmaker matchmaker) { _logger = logger; + _serverConfig = serverConfig.Value; + _redirectorConfig = redirectorConfig.Value; _matchmaker = matchmaker; } public Task StartAsync(CancellationToken cancellationToken) { _matchmaker.Start(); - _logger.LogInformation("Matchmaker is running on {0}:{1}.", + + _logger.LogInformation("Matchmaker is listening on {0}:{1}, the public server ip is {2}:{3}.", _matchmaker.EndPoint.Address, - _matchmaker.EndPoint.Port); + _matchmaker.EndPoint.Port, + _serverConfig.PublicIp, + _serverConfig.PublicPort); + + if (_redirectorConfig.Enabled) + { + _logger.LogWarning(_redirectorConfig.Master + ? "Server redirection is enabled as master, this instance will redirect clients to other nodes." + : "Server redirection is enabled as node, this instance will accept clients."); + } return Task.CompletedTask; } diff --git a/src/Impostor.Server/Net/Messages/Message13Redirect.cs b/src/Impostor.Server/Net/Messages/Message13Redirect.cs new file mode 100644 index 0000000..fe49c2d --- /dev/null +++ b/src/Impostor.Server/Net/Messages/Message13Redirect.cs @@ -0,0 +1,21 @@ +using System.Net; +using Hazel; + +namespace Impostor.Server.Net.Messages +{ + internal static class Message13Redirect + { + public static void Serialize(MessageWriter writer, bool clear, IPEndPoint ipEndPoint) + { + if (clear) + { + writer.Clear(SendOption.Reliable); + } + + writer.StartMessage(MessageFlags.Redirect); + writer.Write(ipEndPoint.Address.GetAddressBytes()); + writer.Write((ushort) ipEndPoint.Port); + writer.EndMessage(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Redirector/ClientManagerRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientManagerRedirector.cs new file mode 100644 index 0000000..f22a624 --- /dev/null +++ b/src/Impostor.Server/Net/Redirector/ClientManagerRedirector.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Hazel; +using Impostor.Server.Net.Manager; +using Microsoft.Extensions.Logging; + +namespace Impostor.Server.Net.Redirector +{ + internal class ClientManagerRedirector : IClientManager + { + private readonly ILogger _logger; + private readonly INodeProvider _nodeProvider; + private readonly HashSet _clients; + + public ClientManagerRedirector(ILogger logger, INodeProvider nodeProvider) + { + _logger = logger; + _nodeProvider = nodeProvider; + _clients = new HashSet(); + } + + public void Create(string name, Connection connection) + { + _logger.LogInformation("Client connected."); + _clients.Add(new ClientRedirector(name, connection, this, _nodeProvider)); + } + + public void Remove(ClientRedirector client) + { + _logger.LogInformation("Client disconnected."); + _clients.Remove(client); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs new file mode 100644 index 0000000..ce85758 --- /dev/null +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -0,0 +1,116 @@ +using System; +using Hazel; +using Impostor.Server.Data; +using Impostor.Server.Net.Messages; +using Impostor.Shared.Innersloth; +using Impostor.Shared.Innersloth.Data; +using Serilog; +using ILogger = Serilog.ILogger; + +namespace Impostor.Server.Net.Redirector +{ + internal class ClientRedirector + { + private static readonly ILogger Logger = Log.ForContext(); + + private readonly string _name; + private readonly Connection _connection; + private readonly ClientManagerRedirector _clientManager; + private readonly INodeProvider _nodeProvider; + + public ClientRedirector(string name, Connection connection, ClientManagerRedirector clientManager, INodeProvider nodeProvider) + { + _name = name; + _connection = connection; + _connection.DataReceived += OnDataReceived; + _connection.Disconnected += OnDisconnected; + _clientManager = clientManager; + _nodeProvider = nodeProvider; + } + + private void OnDataReceived(DataReceivedEventArgs e) + { + try + { + while (true) + { + if (e.Message.Position >= e.Message.Length) + { + break; + } + + OnMessageReceived(e.Message.ReadMessage()); + } + } + catch (Exception ex) + { + Logger.Error(ex, "Exception caught in client data handler."); + } + } + + private void OnMessageReceived(MessageReader message) + { + var flag = message.Tag; + + Logger.Verbose("Server got {0}.", flag); + + switch (flag) + { + case MessageFlags.HostGame: + { + using (var packet = MessageWriter.Get(SendOption.Reliable)) + { + Message13Redirect.Serialize(packet, false, _nodeProvider.Get()); + _connection.Send(packet); + } + break; + } + + case MessageFlags.JoinGame: + { + Message01JoinGame.Deserialize(message, + out var gameCode, + out var unknown); + + using (var packet = MessageWriter.Get(SendOption.Reliable)) + { + var endpoint = _nodeProvider.Find(GameCode.IntToGameName(gameCode)); + if (endpoint == null) + { + Message01JoinGame.SerializeError(packet, false, DisconnectReason.GameMissing); + } + else + { + Message13Redirect.Serialize(packet, false, endpoint); + } + + _connection.Send(packet); + } + break; + } + + case MessageFlags.GetGameListV2: + { + // TODO: Implement. + using (var packet = MessageWriter.Get(SendOption.Reliable)) + { + Message01JoinGame.SerializeError(packet, false, DisconnectReason.Custom, DisconnectMessages.NotImplemented); + _connection.Send(packet); + } + break; + } + + default: + { + Logger.Warning("Received unsupported message flag on the redirector ({0}).", flag); + break; + } + } + } + + private void OnDisconnected(object sender, DisconnectedEventArgs e) + { + _clientManager.Remove(this); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Redirector/INodeProvider.cs b/src/Impostor.Server/Net/Redirector/INodeProvider.cs new file mode 100644 index 0000000..37418e6 --- /dev/null +++ b/src/Impostor.Server/Net/Redirector/INodeProvider.cs @@ -0,0 +1,12 @@ +using System.Net; + +namespace Impostor.Server.Net.Redirector +{ + 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 diff --git a/src/Impostor.Server/Net/Redirector/NodeProviderNoOp.cs b/src/Impostor.Server/Net/Redirector/NodeProviderNoOp.cs new file mode 100644 index 0000000..fa97968 --- /dev/null +++ b/src/Impostor.Server/Net/Redirector/NodeProviderNoOp.cs @@ -0,0 +1,29 @@ +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 diff --git a/src/Impostor.Server/Net/Redirector/NodeProviderRedis.cs b/src/Impostor.Server/Net/Redirector/NodeProviderRedis.cs new file mode 100644 index 0000000..c1ef93c --- /dev/null +++ b/src/Impostor.Server/Net/Redirector/NodeProviderRedis.cs @@ -0,0 +1,68 @@ +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 _nodes; + private readonly object _lock; + private int _currentIndex; + + public NodeProviderRedis(IOptions redirectorConfig, IDistributedCache cache) + { + _cache = cache; + _nodes = new List(); + _lock = new object(); + + 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 diff --git a/src/Impostor.Server/Net/State/ClientPlayer.Events.cs b/src/Impostor.Server/Net/State/ClientPlayer.Events.cs index 87a8028..4404862 100644 --- a/src/Impostor.Server/Net/State/ClientPlayer.Events.cs +++ b/src/Impostor.Server/Net/State/ClientPlayer.Events.cs @@ -4,7 +4,7 @@ using Impostor.Shared.Innersloth; namespace Impostor.Server.Net.State { - public partial class ClientPlayer + internal partial class ClientPlayer { /// /// Triggered when the connected client requests the game listing. diff --git a/src/Impostor.Server/Net/State/ClientPlayer.cs b/src/Impostor.Server/Net/State/ClientPlayer.cs index d9c5c3d..5242cab 100644 --- a/src/Impostor.Server/Net/State/ClientPlayer.cs +++ b/src/Impostor.Server/Net/State/ClientPlayer.cs @@ -5,7 +5,7 @@ using Impostor.Shared.Innersloth.Data; namespace Impostor.Server.Net.State { - public partial class ClientPlayer + internal partial class ClientPlayer { private readonly GameManager _gameManager; diff --git a/src/Impostor.Server/Net/State/Game.Incoming.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs index 7c5f2b5..bf91cc9 100644 --- a/src/Impostor.Server/Net/State/Game.Incoming.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -7,7 +7,7 @@ using Impostor.Shared.Innersloth.Data; namespace Impostor.Server.Net.State { - public partial class Game + internal partial class Game { public void HandleStartGame(MessageReader message) { diff --git a/src/Impostor.Server/Net/State/Game.Outgoing.cs b/src/Impostor.Server/Net/State/Game.Outgoing.cs index c03b3b4..0938ee1 100644 --- a/src/Impostor.Server/Net/State/Game.Outgoing.cs +++ b/src/Impostor.Server/Net/State/Game.Outgoing.cs @@ -5,7 +5,7 @@ using Impostor.Shared.Innersloth.Data; namespace Impostor.Server.Net.State { - public partial class Game + internal partial class Game { private void WriteRemovePlayerMessage(MessageWriter message, bool clear, int playerId, DisconnectReason reason) { diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index 8a60c2f..bb8ff6a 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -5,6 +5,7 @@ using System.Net; using Hazel; using Impostor.Server.Net.Manager; using Impostor.Server.Net.Messages; +using Impostor.Server.Net.Redirector; using Impostor.Shared.Innersloth; using Impostor.Shared.Innersloth.Data; using Serilog; @@ -12,17 +13,19 @@ using ILogger = Serilog.ILogger; namespace Impostor.Server.Net.State { - public partial class Game + internal partial class Game { private static readonly ILogger Logger = Log.ForContext(); private readonly GameManager _gameManager; + private readonly INodeProvider _nodeProvider; private readonly ConcurrentDictionary _players; private readonly HashSet _bannedIps; - public Game(GameManager gameManager, IPEndPoint publicIp, int code, GameOptionsData options) + public Game(GameManager gameManager, INodeProvider nodeProvider, IPEndPoint publicIp, int code, GameOptionsData options) { _gameManager = gameManager; + _nodeProvider = nodeProvider; _players = new ConcurrentDictionary(); _bannedIps = new HashSet(); diff --git a/src/Impostor.Server/Program.cs b/src/Impostor.Server/Program.cs index 2cc7f0c..984c314 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -2,11 +2,11 @@ using Impostor.Server.Data; using Impostor.Server.Net; using Impostor.Server.Net.Manager; +using Impostor.Server.Net.Redirector; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; -using Serilog.Events; namespace Impostor.Server { @@ -19,9 +19,8 @@ namespace Impostor.Server .MinimumLevel.Verbose() #else .MinimumLevel.Information() - -#endif .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) +#endif .Enrich.FromLogContext() .WriteTo.Console() .CreateLogger(); @@ -48,14 +47,43 @@ namespace Impostor.Server .ConfigureAppConfiguration(builder => { builder.AddJsonFile("config.json", true); + builder.AddJsonFile("config.Development.json", true); builder.AddEnvironmentVariables(prefix: "IMPOSTOR_"); builder.AddCommandLine(args); }) .ConfigureServices((host, services) => { - services.Configure(host.Configuration.GetSection("Server")); + var redirector = host.Configuration + .GetSection(ServerRedirectorConfig.Section) + .Get(); + + services.Configure(host.Configuration.GetSection(ServerConfig.Section)); + services.Configure(host.Configuration.GetSection(ServerRedirectorConfig.Section)); - services.AddSingleton(); + if (redirector.Enabled) + { + services.AddSingleton(); + services.AddStackExchangeRedisCache(options => + { + options.Configuration = redirector.Redis; + options.InstanceName = "ImpostorRedis"; + }); + } + else + { + services.AddSingleton(); + } + + if (redirector.Enabled && redirector.Master) + { + services.AddSingleton(); + } + else + { + services.AddSingleton(); + services.AddSingleton(); + } + services.AddSingleton(); services.AddHostedService(); diff --git a/src/Impostor.Server/config.json b/src/Impostor.Server/config.json index f969cbf..5e9f634 100644 --- a/src/Impostor.Server/config.json +++ b/src/Impostor.Server/config.json @@ -4,5 +4,20 @@ "PublicPort": 22023, "ListenIp": "0.0.0.0", "ListenPort": 22023 + }, + "ServerRedirector": { + "Enabled": false, + "Master": true, + "Redis": "127.0.0.1:6379", + "Nodes": [ + { + "Ip": "127.0.0.1", + "Port": 22024 + }, + { + "Ip": "127.0.0.1", + "Port": 22025 + } + ] } } \ No newline at end of file