From a5a67963bef0543990680ce4697524229db56bad Mon Sep 17 00:00:00 2001 From: edmand46 Date: Tue, 20 Dec 2022 12:20:52 -0800 Subject: [PATCH] feat: websockets --- .github/workflows/main.yml | 10 +- Ragon.Core/Application.cs | 20 ++- Ragon.Core/Configuration.cs | 10 +- Ragon.Core/Game/Entity.cs | 18 +-- Ragon.Core/Game/Room.cs | 4 +- Ragon.Core/Handlers/AuthorizationHandler.cs | 2 +- Ragon.Core/Handlers/RoomCreateHandler.cs | 4 +- Ragon.Core/Handlers/RoomJoinHandler.cs | 4 +- .../Handlers/RoomJoinOrCreateHandler.cs | 2 +- Ragon.Core/Handlers/SceneLoadedHandler.cs | 4 +- Ragon.Core/Ragon.Core.csproj | 2 +- Ragon.Relay/Program.cs | 9 +- Ragon.Relay/Ragon.Relay.csproj | 2 +- Ragon.Relay/config.json | 12 -- Ragon.Relay/relay.config.json | 10 ++ Ragon.Server.ENet/ENetConnection.cs | 8 +- Ragon.Server.ENet/ENetServer.cs | 4 +- .../Ragon.Server.NativeWebSockets.csproj | 8 ++ .../WebSocketConnection.cs | 44 +++++++ .../WebSocketReliableChannel.cs | 27 ++++ .../WebSocketServer.cs | 121 ++++++++++++++++++ Ragon.Server/INetworkConnection.cs | 4 +- {Ragon.Core => Ragon.Server/IO}/Executor.cs | 14 +- Ragon.sln | 2 +- 24 files changed, 276 insertions(+), 69 deletions(-) delete mode 100755 Ragon.Relay/config.json create mode 100644 Ragon.Relay/relay.config.json rename Ragon.Server.WebSockets/Ragon.Server.WebSockets.csproj => Ragon.Server.NativeWebSockets/Ragon.Server.NativeWebSockets.csproj (58%) create mode 100644 Ragon.Server.NativeWebSockets/WebSocketConnection.cs create mode 100644 Ragon.Server.NativeWebSockets/WebSocketReliableChannel.cs create mode 100644 Ragon.Server.NativeWebSockets/WebSocketServer.cs rename {Ragon.Core => Ragon.Server/IO}/Executor.cs (86%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 410fedf..9c86863 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.ref }} - release_name: Ragon.SimpleServer-${{ github.ref }} + release_name: Ragon.Relay-${{ github.ref }} prerelease: true build: @@ -53,10 +53,10 @@ jobs: - name: Build shell: bash run: | - release_name="Ragon.SimpleServer-${{ env.TAG }}-${{ matrix.target }}" + release_name="Ragon.Relay-${{ env.TAG }}-${{ matrix.target }}" # Build everything - dotnet publish Ragon.SimpleServer/Ragon.SimpleServer.csproj -c Release --runtime "${{ matrix.target }}" -p:PublishSingleFile=true -o "$release_name" + dotnet publish Ragon.Relay/Ragon.Relay.csproj -c Release --runtime "${{ matrix.target }}" -p:PublishSingleFile=true -o "$release_name" # Pack files 7z a -tzip "${release_name}.zip" "./${release_name}/*" @@ -69,6 +69,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ needs.release.outputs.upload_url }} - asset_path: Ragon.SimpleServer-${{ env.TAG }}-${{ matrix.target }}.zip - asset_name: Ragon.SimpleServer-${{ env.TAG }}-${{ matrix.target }}.zip + asset_path: Ragon.Relay-${{ env.TAG }}-${{ matrix.target }}.zip + asset_name: Ragon.Relay-${{ env.TAG }}-${{ matrix.target }}.zip asset_content_type: application/zip diff --git a/Ragon.Core/Application.cs b/Ragon.Core/Application.cs index d60cd2a..6a76f55 100644 --- a/Ragon.Core/Application.cs +++ b/Ragon.Core/Application.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using NLog; using Ragon.Common; using Ragon.Core.Lobby; +using Ragon.Core.Server; using Ragon.Core.Time; using Ragon.Server; using Ragon.Server.ENet; @@ -13,6 +14,7 @@ public class Application : INetworkListener private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly INetworkServer _server; private readonly Thread _dedicatedThread; + private readonly Executor _executor; private readonly Configuration _configuration; private readonly HandlerRegistry _handlerRegistry; private readonly ILobby _lobby; @@ -22,6 +24,7 @@ public class Application : INetworkListener public Application(Configuration configuration) { _configuration = configuration; + _executor = new Executor(); _dedicatedThread = new Thread(Execute); _dedicatedThread.IsBackground = true; _contexts = new Dictionary(); @@ -29,20 +32,24 @@ public class Application : INetworkListener _lobby = new LobbyInMemory(); _loop = new Loop(); - if (configuration.Socket == "enet") + if (configuration.ServerType == "enet") _server = new ENetServer(); + + if (configuration.ServerType == "websocket") + _server = new NativeWebSocketServer(_executor); - Debug.Assert(_server != null, $"Socket type not supported: {configuration.Socket}. Supported: [enet, websocket]"); + Debug.Assert(_server != null, $"Socket type not supported: {configuration.ServerType}. Supported: [enet, websocket]"); } public void Execute() { while (true) { + _executor.Execute(); _loop.Tick(); _server.Poll(); - - Thread.Sleep((int) 1000.0f / _configuration.SendRate); + + Thread.Sleep((int)1000.0f / _configuration.ServerTickRate); } } @@ -51,7 +58,7 @@ public class Application : INetworkListener var networkConfiguration = new NetworkConfiguration() { LimitConnections = _configuration.LimitConnections, - Protocol = RagonVersion.Parse(_configuration.Protocol), + Protocol = RagonVersion.Parse(_configuration.GameProtocol), Address = "0.0.0.0", Port = _configuration.Port, }; @@ -86,9 +93,10 @@ public class Application : INetworkListener if (room != null) { room.RemovePlayer(context.RoomPlayer); - + _lobby.RemoveIfEmpty(room); } + context.Dispose(); } } diff --git a/Ragon.Core/Configuration.cs b/Ragon.Core/Configuration.cs index 2b341a3..cdaf8e3 100644 --- a/Ragon.Core/Configuration.cs +++ b/Ragon.Core/Configuration.cs @@ -6,13 +6,11 @@ namespace Ragon.Core; [Serializable] public struct Configuration { - public string Key; - public string Protocol; - public string Socket; - public ushort SendRate; + public string ServerKey; + public string ServerType; + public ushort ServerTickRate; + public string GameProtocol; public ushort Port; - public int SkipTimeout; - public int ReconnectTimeout; public int LimitConnections; public int LimitPlayersPerRoom; public int LimitRooms; diff --git a/Ragon.Core/Game/Entity.cs b/Ragon.Core/Game/Entity.cs index aba1470..bed6d88 100644 --- a/Ragon.Core/Game/Entity.cs +++ b/Ragon.Core/Game/Entity.cs @@ -54,7 +54,7 @@ public class Entity writer.WriteData(ref data); var sendData = writer.ToArray(); - roomPlayer.Connection.ReliableChannel.Send(sendData); + roomPlayer.Connection.Reliable.Send(sendData); } } @@ -68,14 +68,14 @@ public class Entity serializer.WriteUShort(Type); serializer.WriteUShort(Id); serializer.WriteUShort(Owner.Connection.Id); - + ReadOnlySpan entityPayload = Payload.AsSpan(); serializer.WriteUShort((ushort)entityPayload.Length); serializer.WriteData(ref entityPayload); var sendData = serializer.ToArray(); foreach (var player in room.ReadyPlayersList) - player.Connection.ReliableChannel.Send(sendData); + player.Connection.Reliable.Send(sendData); } public void Destroy(byte[] payload) @@ -91,7 +91,7 @@ public class Entity var sendData = serializer.ToArray(); foreach (var player in room.ReadyPlayersList) - player.Connection.ReliableChannel.Send(sendData); + player.Connection.Reliable.Send(sendData); } public void ReplicateEvent( @@ -114,7 +114,7 @@ public class Entity serializer.WriteData(ref payload); var sendData = serializer.ToArray(); - targetPlayer.Connection.ReliableChannel.Send(sendData); + targetPlayer.Connection.Reliable.Send(sendData); } public void ReplicateEvent( @@ -155,7 +155,7 @@ public class Entity { case RagonTarget.Owner: { - Owner.Connection.ReliableChannel.Send(sendData); + Owner.Connection.Reliable.Send(sendData); break; } case RagonTarget.ExceptOwner: @@ -163,7 +163,7 @@ public class Entity foreach (var roomPlayer in room.ReadyPlayersList) { if (roomPlayer.Connection.Id != Owner.Connection.Id) - roomPlayer.Connection.ReliableChannel.Send(sendData); + roomPlayer.Connection.Reliable.Send(sendData); } break; @@ -173,7 +173,7 @@ public class Entity foreach (var roomPlayer in room.ReadyPlayersList) { if (roomPlayer.Connection.Id != caller.Connection.Id) - roomPlayer.Connection.ReliableChannel.Send(sendData); + roomPlayer.Connection.Reliable.Send(sendData); } break; @@ -181,7 +181,7 @@ public class Entity case RagonTarget.All: { foreach (var roomPlayer in room.ReadyPlayersList) - roomPlayer.Connection.ReliableChannel.Send(sendData); + roomPlayer.Connection.Reliable.Send(sendData); break; } } diff --git a/Ragon.Core/Game/Room.cs b/Ragon.Core/Game/Room.cs index 2ec5c94..26a3ccf 100644 --- a/Ragon.Core/Game/Room.cs +++ b/Ragon.Core/Game/Room.cs @@ -83,7 +83,7 @@ public class Room: IAction var sendData = Writer.ToArray(); foreach (var roomPlayer in ReadyPlayersList) - roomPlayer.Connection.UnreliableChannel.Send(sendData); + roomPlayer.Connection.Unreliable.Send(sendData); } } @@ -161,6 +161,6 @@ public class Room: IAction public void Broadcast(byte[] data) { foreach (var readyPlayer in ReadyPlayersList) - readyPlayer.Connection.ReliableChannel.Send(data); + readyPlayer.Connection.Reliable.Send(data); } } \ No newline at end of file diff --git a/Ragon.Core/Handlers/AuthorizationHandler.cs b/Ragon.Core/Handlers/AuthorizationHandler.cs index 6ab9bc2..05613e2 100644 --- a/Ragon.Core/Handlers/AuthorizationHandler.cs +++ b/Ragon.Core/Handlers/AuthorizationHandler.cs @@ -32,7 +32,7 @@ public sealed class AuthorizationHandler: IHandler writer.WriteString(playerName); var sendData = writer.ToArray(); - context.Connection.ReliableChannel.Send(sendData); + context.Connection.Reliable.Send(sendData); _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} authorized"); } diff --git a/Ragon.Core/Handlers/RoomCreateHandler.cs b/Ragon.Core/Handlers/RoomCreateHandler.cs index 950508d..8b668f1 100644 --- a/Ragon.Core/Handlers/RoomCreateHandler.cs +++ b/Ragon.Core/Handlers/RoomCreateHandler.cs @@ -31,7 +31,7 @@ public sealed class CreateHandler: IHandler writer.WriteString($"Room with id {roomId} already exists"); var sendData = writer.ToArray(); - context.Connection.ReliableChannel.Send(sendData); + context.Connection.Reliable.Send(sendData); _logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} join failed to room {roomId}, room already exist"); return; @@ -79,6 +79,6 @@ public sealed class CreateHandler: IHandler writer.WriteString(room.Info.Map); var sendData = writer.ToArray(); - player.Connection.ReliableChannel.Send(sendData); + player.Connection.Reliable.Send(sendData); } } \ No newline at end of file diff --git a/Ragon.Core/Handlers/RoomJoinHandler.cs b/Ragon.Core/Handlers/RoomJoinHandler.cs index 43784d7..74f9e25 100644 --- a/Ragon.Core/Handlers/RoomJoinHandler.cs +++ b/Ragon.Core/Handlers/RoomJoinHandler.cs @@ -47,7 +47,7 @@ public sealed class JoinHandler : IHandler writer.WriteString(room.Info.Map); var sendData = writer.ToArray(); - player.Connection.ReliableChannel.Send(sendData); + player.Connection.Reliable.Send(sendData); } private void JoinFailed(LobbyPlayer player, RagonSerializer writer) @@ -57,6 +57,6 @@ public sealed class JoinHandler : IHandler writer.WriteString($"Room not exists"); var sendData = writer.ToArray(); - player.Connection.ReliableChannel.Send(sendData); + player.Connection.Reliable.Send(sendData); } } \ No newline at end of file diff --git a/Ragon.Core/Handlers/RoomJoinOrCreateHandler.cs b/Ragon.Core/Handlers/RoomJoinOrCreateHandler.cs index e154c2b..0ef7502 100644 --- a/Ragon.Core/Handlers/RoomJoinOrCreateHandler.cs +++ b/Ragon.Core/Handlers/RoomJoinOrCreateHandler.cs @@ -74,7 +74,7 @@ public sealed class JoinOrCreateHandler : IHandler writer.WriteString(room.Info.Map); var sendData = writer.ToArray(); - player.Connection.ReliableChannel.Send(sendData); + player.Connection.Reliable.Send(sendData); _logger.Trace($"Joined to room {room.Id}"); } diff --git a/Ragon.Core/Handlers/SceneLoadedHandler.cs b/Ragon.Core/Handlers/SceneLoadedHandler.cs index bba8e10..0ff1a31 100644 --- a/Ragon.Core/Handlers/SceneLoadedHandler.cs +++ b/Ragon.Core/Handlers/SceneLoadedHandler.cs @@ -88,7 +88,7 @@ public sealed class SceneLoadedHandler : IHandler foreach (var awaiter in room.ReadyPlayersList) { if (awaiter != roomPlayer) - awaiter.Connection.ReliableChannel.Send(sendData); + awaiter.Connection.Reliable.Send(sendData); } } @@ -118,6 +118,6 @@ public sealed class SceneLoadedHandler : IHandler var sendData = writer.ToArray(); foreach (var player in receviersList) - player.Connection.ReliableChannel.Send(sendData); + player.Connection.Reliable.Send(sendData); } } \ No newline at end of file diff --git a/Ragon.Core/Ragon.Core.csproj b/Ragon.Core/Ragon.Core.csproj index 95b0d6c..b1953c6 100644 --- a/Ragon.Core/Ragon.Core.csproj +++ b/Ragon.Core/Ragon.Core.csproj @@ -14,7 +14,7 @@ - + diff --git a/Ragon.Relay/Program.cs b/Ragon.Relay/Program.cs index 2c9e8fd..38c5874 100755 --- a/Ragon.Relay/Program.cs +++ b/Ragon.Relay/Program.cs @@ -10,12 +10,17 @@ namespace Ragon.Relay static void Main(string[] args) { var logger = LogManager.GetLogger("Ragon.Relay"); + logger.Info("Relay Application"); - var configuration = Configuration.Load("config.json"); + + var configuration = Configuration.Load("relay.config.json"); var relay = new Application(configuration); - relay.Start(); + logger.Info("Started"); + relay.Start(); + Console.ReadKey(); + relay.Stop(); logger.Info("Stopped"); } diff --git a/Ragon.Relay/Ragon.Relay.csproj b/Ragon.Relay/Ragon.Relay.csproj index 3813ce0..851f760 100755 --- a/Ragon.Relay/Ragon.Relay.csproj +++ b/Ragon.Relay/Ragon.Relay.csproj @@ -14,7 +14,7 @@ Always - + Always diff --git a/Ragon.Relay/config.json b/Ragon.Relay/config.json deleted file mode 100755 index b348e42..0000000 --- a/Ragon.Relay/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "key": "defaultkey", - "socket": "enet", - "protocol": "1.0.0", - "sendRate": 50, - "port": 4444, - "skipTimeout": 60, - "reconnectTimeout": 300, - "limitConnections": 4095, - "limitPlayersPerRoom": 20, - "limitRooms": 200 -} \ No newline at end of file diff --git a/Ragon.Relay/relay.config.json b/Ragon.Relay/relay.config.json new file mode 100644 index 0000000..7929c72 --- /dev/null +++ b/Ragon.Relay/relay.config.json @@ -0,0 +1,10 @@ +{ + "serverKey": "defaultkey", + "serverType": "websocket", + "serverTickRate": 20, + "gameProtocol": "1.0.0", + "port": 5000, + "limitConnections": 4095, + "limitPlayersPerRoom": 20, + "limitRooms": 200 +} \ No newline at end of file diff --git a/Ragon.Server.ENet/ENetConnection.cs b/Ragon.Server.ENet/ENetConnection.cs index 127394e..dde4943 100644 --- a/Ragon.Server.ENet/ENetConnection.cs +++ b/Ragon.Server.ENet/ENetConnection.cs @@ -5,13 +5,13 @@ namespace Ragon.Server.ENet; public sealed class ENetConnection: INetworkConnection { public ushort Id { get; } - public INetworkChannel ReliableChannel { get; private set; } - public INetworkChannel UnreliableChannel { get; private set; } + public INetworkChannel Reliable { get; private set; } + public INetworkChannel Unreliable { get; private set; } public ENetConnection(Peer peer) { Id = (ushort) peer.ID; - ReliableChannel = new ENetReliableChannel(peer, 0); - UnreliableChannel = new ENetUnreliableChannel(peer, 1); + Reliable = new ENetReliableChannel(peer, 0); + Unreliable = new ENetUnreliableChannel(peer, 1); } } \ No newline at end of file diff --git a/Ragon.Server.ENet/ENetServer.cs b/Ragon.Server.ENet/ENetServer.cs index f842ea1..0de6247 100755 --- a/Ragon.Server.ENet/ENetServer.cs +++ b/Ragon.Server.ENet/ENetServer.cs @@ -63,7 +63,8 @@ namespace Ragon.Server.ENet { if (!IsValidProtocol(_event.Data)) { - _logger.Warn("Mismatched protocol, close connection"); + _logger.Warn($"Mismatched protocol Server: {RagonVersion.Parse(_protocol)} Client: {RagonVersion.Parse(_event.Data)}, close connection"); + _event.Peer.DisconnectNow(0); break; } @@ -109,7 +110,6 @@ namespace Ragon.Server.ENet private bool IsValidProtocol(uint protocol) { - Console.WriteLine($"{protocol} {_protocol}"); return protocol == _protocol; } } diff --git a/Ragon.Server.WebSockets/Ragon.Server.WebSockets.csproj b/Ragon.Server.NativeWebSockets/Ragon.Server.NativeWebSockets.csproj similarity index 58% rename from Ragon.Server.WebSockets/Ragon.Server.WebSockets.csproj rename to Ragon.Server.NativeWebSockets/Ragon.Server.NativeWebSockets.csproj index 13c6238..b24f098 100644 --- a/Ragon.Server.WebSockets/Ragon.Server.WebSockets.csproj +++ b/Ragon.Server.NativeWebSockets/Ragon.Server.NativeWebSockets.csproj @@ -7,4 +7,12 @@ Ragon.WebSockets + + + + + + + + diff --git a/Ragon.Server.NativeWebSockets/WebSocketConnection.cs b/Ragon.Server.NativeWebSockets/WebSocketConnection.cs new file mode 100644 index 0000000..c644447 --- /dev/null +++ b/Ragon.Server.NativeWebSockets/WebSocketConnection.cs @@ -0,0 +1,44 @@ +using System.Net.WebSockets; +using NLog; + +namespace Ragon.Server.NativeWebSockets; + +public sealed class WebSocketConnection : INetworkConnection +{ + private Logger _logger = LogManager.GetCurrentClassLogger(); + public ushort Id { get; } + public INetworkChannel Reliable { get; private set; } + public INetworkChannel Unreliable { get; private set; } + + public WebSocket Socket { get; private set; } + private WebSocketReliableChannel[] _channels; + + public WebSocketConnection(WebSocket webSocket, ushort peerId) + { + Id = peerId; + Socket = webSocket; + + var reliableChannel = new WebSocketReliableChannel(webSocket); + var unreliableChannel = new WebSocketReliableChannel(webSocket); + + _channels = new[] { reliableChannel, unreliableChannel }; + + Reliable = reliableChannel; + Unreliable = unreliableChannel; + } + + public async Task Flush() + { + foreach (var channel in _channels) + { + try + { + await channel.Flush(); + } + catch (Exception ex) + { + _logger.Error(ex); + } + } + } +} \ No newline at end of file diff --git a/Ragon.Server.NativeWebSockets/WebSocketReliableChannel.cs b/Ragon.Server.NativeWebSockets/WebSocketReliableChannel.cs new file mode 100644 index 0000000..a456eea --- /dev/null +++ b/Ragon.Server.NativeWebSockets/WebSocketReliableChannel.cs @@ -0,0 +1,27 @@ +using System.Net.WebSockets; +using Ragon.Server; + +namespace Ragon.Server.NativeWebSockets; + +public class WebSocketReliableChannel : INetworkChannel +{ + private Queue _queue; + private WebSocket _socket; + + public WebSocketReliableChannel(WebSocket webSocket) + { + _socket = webSocket; + _queue = new Queue(512); + } + + public void Send(byte[] data) + { + _queue.Enqueue(data); + } + + public async Task Flush() + { + while (_queue.TryDequeue(out var sendData) && _socket.State == WebSocketState.Open) + await _socket.SendAsync(sendData, WebSocketMessageType.Binary, WebSocketMessageFlags.EndOfMessage, CancellationToken.None); + } +} \ No newline at end of file diff --git a/Ragon.Server.NativeWebSockets/WebSocketServer.cs b/Ragon.Server.NativeWebSockets/WebSocketServer.cs new file mode 100644 index 0000000..b7a99e4 --- /dev/null +++ b/Ragon.Server.NativeWebSockets/WebSocketServer.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Net.WebSockets; +using NLog; +using Ragon.Common; +using Ragon.Core.Server; +using Ragon.Server; +using Ragon.Server.NativeWebSockets; + +namespace Ragon.Core; + +public class NativeWebSocketServer : INetworkServer +{ + private ILogger _logger = LogManager.GetCurrentClassLogger(); + private INetworkListener _networkListener; + private Stack _sequencer; + private Executor _executor; + private HttpListener _httpListener; + private WebSocketConnection[] _connections; + private ushort _lastPeerId; + private CancellationTokenSource _cancellationTokenSource; + + public NativeWebSocketServer(Executor executor) + { + _sequencer = new Stack(); + _connections = Array.Empty(); + _executor = executor; + } + + public async Task StartAccept(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + var context = await _httpListener.GetContextAsync(); + if (!context.Request.IsWebSocketRequest) continue; + + var webSocketContext = await context.AcceptWebSocketAsync(null); + var webSocket = webSocketContext.WebSocket; + + var peerId = _sequencer.Pop(); + var connection = new WebSocketConnection(webSocket, peerId); + + _lastPeerId = peerId; + _connections[peerId] = connection; + _networkListener.OnConnected(connection); + _executor.Run(StartListen(connection, cancellationToken)); + } + } + + async Task StartListen(WebSocketConnection connection, CancellationToken cancellationToken) + { + var webSocket = connection.Socket; + var bytes = new byte[2048]; + var buffer = new Memory(bytes); + while ( + webSocket.State == WebSocketState.Open || + !cancellationToken.IsCancellationRequested) + { + try + { + var result = await webSocket.ReceiveAsync(buffer, cancellationToken); + var dataRaw = buffer.Slice(0, result.Count); + + _networkListener.OnData(connection, dataRaw.ToArray()); + } + catch (Exception ex) + { + break; + } + } + + _sequencer.Push(connection.Id); + _networkListener.OnDisconnected(connection); + } + + public async void Poll() + { + foreach (var conn in _connections) + { + if (conn != null) + { + await conn.Flush(); + } + } + } + + public void Start( + INetworkListener listener, + NetworkConfiguration configuration + ) + { + _networkListener = listener; + _cancellationTokenSource = new CancellationTokenSource(); + + var limit = (ushort) configuration.LimitConnections; + for (ushort i = limit; i != 0; i--) + _sequencer.Push(i); + + _sequencer.Push(0); + + _connections = new WebSocketConnection[configuration.LimitConnections]; + + _httpListener = new HttpListener(); + _httpListener.Prefixes.Add($"http://127.0.0.1:{configuration.Port}/"); + _httpListener.Start(); + + _executor.Run(StartAccept(_cancellationTokenSource.Token)); + + var protocolDecoded = RagonVersion.Parse(configuration.Protocol); + _logger.Info($"Network listening on http://*:{configuration.Port}/"); + _logger.Info($"Protocol: {protocolDecoded}"); + } + + public void Stop() + { + _cancellationTokenSource.Cancel(); + _httpListener.Stop(); + } +} \ No newline at end of file diff --git a/Ragon.Server/INetworkConnection.cs b/Ragon.Server/INetworkConnection.cs index bb1ecf0..5a32411 100644 --- a/Ragon.Server/INetworkConnection.cs +++ b/Ragon.Server/INetworkConnection.cs @@ -3,6 +3,6 @@ namespace Ragon.Server; public interface INetworkConnection { public ushort Id { get; } - public INetworkChannel ReliableChannel { get; } - public INetworkChannel UnreliableChannel { get; } + public INetworkChannel Reliable { get; } + public INetworkChannel Unreliable { get; } } \ No newline at end of file diff --git a/Ragon.Core/Executor.cs b/Ragon.Server/IO/Executor.cs similarity index 86% rename from Ragon.Core/Executor.cs rename to Ragon.Server/IO/Executor.cs index 1023959..f5d80de 100644 --- a/Ragon.Core/Executor.cs +++ b/Ragon.Server/IO/Executor.cs @@ -1,20 +1,17 @@ -using System; -using System.Collections.Generic; using System.Threading.Channels; -using System.Threading.Tasks; -using NLog.LayoutRenderers.Wrappers; -namespace Ragon.Core; +namespace Ragon.Core.Server; public class Executor: TaskScheduler { private ChannelReader _reader; private ChannelWriter _writer; private Queue _pendingTasks; - + private TaskFactory _taskFactory; + public void Run(Task task) { - task.Start(this); + _taskFactory.StartNew(() => task); } public Executor() @@ -22,7 +19,8 @@ public class Executor: TaskScheduler var channel = Channel.CreateUnbounded(); _reader = channel.Reader; _writer = channel.Writer; - + + _taskFactory = new TaskFactory(this); _pendingTasks = new Queue(); } diff --git a/Ragon.sln b/Ragon.sln index 429c64c..87f940f 100755 --- a/Ragon.sln +++ b/Ragon.sln @@ -8,7 +8,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server", "Ragon.Serve EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Core", "Ragon.Core\Ragon.Core.csproj", "{F4AA86B9-2486-4B53-BA77-43D958A2FDC3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server.WebSockets", "Ragon.Server.WebSockets\Ragon.Server.WebSockets.csproj", "{81050343-A9B8-487B-86C8-7A5B7DD9C39B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server.NativeWebSockets", "Ragon.Server.NativeWebSockets\Ragon.Server.NativeWebSockets.csproj", "{81050343-A9B8-487B-86C8-7A5B7DD9C39B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ragon.Server.ENet", "Ragon.Server.ENet\Ragon.Server.ENet.csproj", "{DD79AC4F-9E5C-4938-850E-805D537E68D0}" EndProject