✨ http-commands
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
namespace Ragon.Relay;
|
||||
|
||||
public class KickPlayerCommand
|
||||
{
|
||||
public string Id;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using Ragon.Server.Room;
|
||||
|
||||
namespace Ragon.Relay;
|
||||
|
||||
public class RelayRoomPlugin: IRoomPlugin
|
||||
public class RelayRoomPlugin: BaseRoomPlugin
|
||||
{
|
||||
public void Tick(float dt)
|
||||
{
|
||||
|
||||
@@ -1,41 +1,24 @@
|
||||
using System.Net.Http;
|
||||
using Ragon.Server;
|
||||
using Ragon.Server.Lobby;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Ragon.Server.Plugin;
|
||||
using Ragon.Server.Room;
|
||||
|
||||
namespace Ragon.Relay;
|
||||
|
||||
public class RelayServerPlugin: IServerPlugin
|
||||
public class RelayServerPlugin: BaseServerPlugin
|
||||
{
|
||||
private HttpClient httpClient;
|
||||
public IRoomPlugin CreateRoomPlugin(RoomInformation information)
|
||||
public override bool OnCommand(string command, string payload)
|
||||
{
|
||||
return new RelayRoomPlugin();
|
||||
Console.WriteLine(command);
|
||||
if (command == "kick-player")
|
||||
{
|
||||
var commandPayload = JsonConvert.DeserializeObject<KickPlayerCommand>(payload);
|
||||
var player = GetPlayerById(commandPayload.Id);
|
||||
if (player != null)
|
||||
player.Connection.Close();
|
||||
else
|
||||
Console.WriteLine($"Player not found with Id {commandPayload.Id}");
|
||||
}
|
||||
|
||||
public RelayServerPlugin()
|
||||
{
|
||||
httpClient = new HttpClient();
|
||||
}
|
||||
|
||||
public bool OnRoomCreate(RagonLobbyPlayer player, RagonRoom room)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnRoomRemove(RagonLobbyPlayer player, RagonRoom room)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnRoomLeave(RagonRoomPlayer player, RagonRoom room)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnRoomJoin(RagonRoomPlayer player, RagonRoom room)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
"serverTickRate": 30,
|
||||
"gameProtocol": "1.0.0",
|
||||
"port": 5000,
|
||||
"httpPort": 5001,
|
||||
"httpKey": "defaultkey",
|
||||
"limitConnections": 4095,
|
||||
"limitPlayersPerRoom": 20,
|
||||
"limitRooms": 200,
|
||||
|
||||
@@ -26,17 +26,19 @@ namespace Ragon.Server.Handler;
|
||||
public sealed class AuthorizationOperation: IRagonOperation
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly WebHookPlugin _webHook;
|
||||
private readonly RagonWebHookPlugin _ragonWebHook;
|
||||
private readonly RagonContextObserver _contextObserver;
|
||||
private readonly Configuration _configuration;
|
||||
private readonly RagonBuffer _writer;
|
||||
|
||||
public AuthorizationOperation(
|
||||
WebHookPlugin webHook,
|
||||
public AuthorizationOperation(RagonWebHookPlugin ragonWebHook,
|
||||
RagonContextObserver contextObserver,
|
||||
RagonBuffer writer,
|
||||
Configuration configuration)
|
||||
{
|
||||
_webHook = webHook;
|
||||
_ragonWebHook = ragonWebHook;
|
||||
_configuration = configuration;
|
||||
_contextObserver = contextObserver;
|
||||
_writer = writer;
|
||||
}
|
||||
|
||||
@@ -60,10 +62,10 @@ public sealed class AuthorizationOperation: IRagonOperation
|
||||
|
||||
if (key == _configuration.ServerKey)
|
||||
{
|
||||
if (_webHook.RequestAuthorization(context, name, payload))
|
||||
if (_ragonWebHook.RequestAuthorization(context, name, payload))
|
||||
return;
|
||||
|
||||
var lobbyPlayer = new RagonLobbyPlayer(Guid.NewGuid().ToString(), name, payload);
|
||||
var lobbyPlayer = new RagonLobbyPlayer(context.Connection, Guid.NewGuid().ToString(), name, payload);
|
||||
context.SetPlayer(lobbyPlayer);
|
||||
|
||||
Approve(context);
|
||||
@@ -78,6 +80,8 @@ public sealed class AuthorizationOperation: IRagonOperation
|
||||
{
|
||||
context.ConnectionStatus = ConnectionStatus.Authorized;
|
||||
|
||||
_contextObserver.OnAuthorized(context);
|
||||
|
||||
var playerId = context.LobbyPlayer.Id;
|
||||
var playerName = context.LobbyPlayer.Name;
|
||||
var playerPayload = context.LobbyPlayer.Payload;
|
||||
|
||||
@@ -28,12 +28,12 @@ public sealed class RoomCreateOperation: IRagonOperation
|
||||
private readonly RagonRoomParameters _roomParameters = new();
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly IServerPlugin _serverPlugin;
|
||||
private readonly WebHookPlugin _webHookPlugin;
|
||||
private readonly RagonWebHookPlugin _ragonWebHookPlugin;
|
||||
|
||||
public RoomCreateOperation(IServerPlugin serverPlugin, WebHookPlugin webHook)
|
||||
public RoomCreateOperation(IServerPlugin serverPlugin, RagonWebHookPlugin ragonWebHook)
|
||||
{
|
||||
_serverPlugin = serverPlugin;
|
||||
_webHookPlugin = webHook;
|
||||
_ragonWebHookPlugin = ragonWebHook;
|
||||
}
|
||||
|
||||
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
|
||||
@@ -79,11 +79,13 @@ public sealed class RoomCreateOperation: IRagonOperation
|
||||
var roomPlugin = _serverPlugin.CreateRoomPlugin(information);
|
||||
var room = new RagonRoom(roomId, information, roomPlugin);
|
||||
|
||||
roomPlayer.OnAttached(room);
|
||||
|
||||
context.Scheduler.Run(room);
|
||||
context.Lobby.Persist(room);
|
||||
context.SetRoom(room, roomPlayer);
|
||||
|
||||
_webHookPlugin.RoomCreated(context, room);
|
||||
_ragonWebHookPlugin.RoomCreated(context, room, roomPlayer);
|
||||
|
||||
_logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} create room {room.Id} with map {information.Map}");
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@ public sealed class RoomJoinOperation : IRagonOperation
|
||||
{
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly IServerPlugin _serverPlugin;
|
||||
private readonly WebHookPlugin _webHookPlugin;
|
||||
private readonly RagonWebHookPlugin _ragonWebHookPlugin;
|
||||
|
||||
public RoomJoinOperation(IServerPlugin serverPlugin, WebHookPlugin plugin)
|
||||
public RoomJoinOperation(IServerPlugin serverPlugin, RagonWebHookPlugin plugin)
|
||||
{
|
||||
_serverPlugin = serverPlugin;
|
||||
_webHookPlugin = plugin;
|
||||
_ragonWebHookPlugin = plugin;
|
||||
}
|
||||
|
||||
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
|
||||
@@ -53,7 +53,7 @@ public sealed class RoomJoinOperation : IRagonOperation
|
||||
if (!_serverPlugin.OnRoomJoin(player, existsRoom))
|
||||
return;
|
||||
|
||||
_webHookPlugin.RoomJoined(context, existsRoom, player);
|
||||
_ragonWebHookPlugin.RoomJoined(context, existsRoom, player);
|
||||
|
||||
JoinSuccess(context, existsRoom, writer);
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
|
||||
private readonly RagonRoomParameters _roomParameters = new();
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly IServerPlugin _serverPlugin;
|
||||
private readonly WebHookPlugin _webHookPlugin;
|
||||
private readonly RagonWebHookPlugin _ragonWebHookPlugin;
|
||||
|
||||
public RoomJoinOrCreateOperation(IServerPlugin serverPlugin, WebHookPlugin plugin)
|
||||
public RoomJoinOrCreateOperation(IServerPlugin serverPlugin, RagonWebHookPlugin plugin)
|
||||
{
|
||||
_serverPlugin = serverPlugin;
|
||||
_webHookPlugin = plugin;
|
||||
_ragonWebHookPlugin = plugin;
|
||||
}
|
||||
|
||||
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
|
||||
@@ -54,7 +54,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
|
||||
var player = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name);
|
||||
context.SetRoom(existsRoom, player);
|
||||
|
||||
_webHookPlugin.RoomJoined(context, existsRoom, player);
|
||||
_ragonWebHookPlugin.RoomJoined(context, existsRoom, player);
|
||||
|
||||
JoinSuccess(player, existsRoom, writer);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public sealed class RoomJoinOrCreateOperation : IRagonOperation
|
||||
var roomPlugin = _serverPlugin.CreateRoomPlugin(information);
|
||||
var room = new RagonRoom(roomId, information, roomPlugin);
|
||||
|
||||
_webHookPlugin.RoomCreated(context, room);
|
||||
_ragonWebHookPlugin.RoomCreated(context, room, roomPlayer);
|
||||
|
||||
context.Lobby.Persist(room);
|
||||
context.Scheduler.Run(room);
|
||||
|
||||
@@ -25,11 +25,11 @@ public sealed class RoomLeaveOperation: IRagonOperation
|
||||
{
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly IServerPlugin _serverPlugin;
|
||||
private readonly WebHookPlugin _webHookPlugin;
|
||||
public RoomLeaveOperation(IServerPlugin serverPlugin, WebHookPlugin plugin)
|
||||
private readonly RagonWebHookPlugin _ragonWebHookPlugin;
|
||||
public RoomLeaveOperation(IServerPlugin serverPlugin, RagonWebHookPlugin plugin)
|
||||
{
|
||||
_serverPlugin = serverPlugin;
|
||||
_webHookPlugin = plugin;
|
||||
_ragonWebHookPlugin = plugin;
|
||||
}
|
||||
|
||||
public void Handle(RagonContext context, RagonBuffer reader, RagonBuffer writer)
|
||||
@@ -40,7 +40,7 @@ public sealed class RoomLeaveOperation: IRagonOperation
|
||||
if (room != null)
|
||||
{
|
||||
_serverPlugin.OnRoomLeave(roomPlayer, room);
|
||||
_webHookPlugin.RoomLeaved(context, room, roomPlayer);
|
||||
_ragonWebHookPlugin.RoomLeaved(context, room, roomPlayer);
|
||||
context.Room?.DetachPlayer(roomPlayer);
|
||||
_logger.Trace($"Player {context.Connection.Id}|{context.LobbyPlayer.Name} leaved from {room.Id}");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
using NLog;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Ragon.Server.IO;
|
||||
using Ragon.Server.Plugin;
|
||||
|
||||
namespace Ragon.Server.Http;
|
||||
|
||||
public class RagonHttpServer
|
||||
{
|
||||
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly IExecutor _executor;
|
||||
private readonly IServerPlugin _serverPlugin;
|
||||
private HttpListener _httpListener;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
public RagonHttpServer(IExecutor executor, IServerPlugin serverPlugin)
|
||||
{
|
||||
_serverPlugin = serverPlugin;
|
||||
_executor = executor;
|
||||
}
|
||||
|
||||
public async void StartAccept(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var context = await _httpListener.GetContextAsync();
|
||||
|
||||
if (context.Request.HttpMethod != "POST")
|
||||
{
|
||||
context.Response.StatusCode = 404;
|
||||
context.Response.ContentLength64 = 0;
|
||||
context.Response.Close();
|
||||
}
|
||||
|
||||
var request = context.Request;
|
||||
var reader = new StreamReader(request.InputStream, request.ContentEncoding);
|
||||
var rawJson = await reader.ReadToEndAsync();
|
||||
var httpCommand = JsonDocument.Parse(rawJson);
|
||||
if (httpCommand != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var command = httpCommand.RootElement.GetProperty("command");
|
||||
var payload = httpCommand.RootElement.GetProperty("payload");
|
||||
|
||||
if (_serverPlugin.OnCommand(command.GetString() ?? "none", payload.GetRawText()))
|
||||
{
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.ContentLength64 = 0;
|
||||
context.Response.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
context.Response.ContentLength64 = 0;
|
||||
context.Response.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex);
|
||||
|
||||
context.Response.StatusCode = 505;
|
||||
context.Response.ContentLength64 = 0;
|
||||
context.Response.Close();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
context.Response.StatusCode = 403;
|
||||
context.Response.ContentLength64 = 0;
|
||||
context.Response.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Start(Configuration configuration)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_logger.Info($"Listen at http://0.0.0.0:{configuration.HttpPort}/");
|
||||
|
||||
_httpListener = new HttpListener();
|
||||
_httpListener.Prefixes.Add($"http://127.0.0.1:{configuration.HttpPort}/");
|
||||
_httpListener.Start();
|
||||
|
||||
_executor.Run(() => StartAccept(_cancellationTokenSource.Token), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
_httpListener.Stop();
|
||||
}
|
||||
}
|
||||
@@ -20,19 +20,24 @@ namespace Ragon.Server.IO;
|
||||
|
||||
public class Executor : TaskScheduler, IExecutor
|
||||
{
|
||||
private ChannelReader<Task> _reader;
|
||||
private ChannelWriter<Task> _writer;
|
||||
private Queue<Task> _pendingTasks;
|
||||
private TaskFactory _taskFactory;
|
||||
private readonly ChannelReader<Task> _reader;
|
||||
private readonly ChannelWriter<Task> _writer;
|
||||
private readonly Queue<Task> _pendingTasks;
|
||||
private readonly TaskFactory _taskFactory;
|
||||
|
||||
public Task Run(Action action)
|
||||
public Task Run(Action action, TaskCreationOptions task = TaskCreationOptions.None)
|
||||
{
|
||||
return _taskFactory.StartNew(action);
|
||||
return _taskFactory.StartNew(action, task);
|
||||
}
|
||||
|
||||
public Executor()
|
||||
{
|
||||
var channel = Channel.CreateUnbounded<Task>();
|
||||
var channel = Channel.CreateUnbounded<Task>(new UnboundedChannelOptions()
|
||||
{
|
||||
SingleReader = true,
|
||||
SingleWriter = true,
|
||||
});
|
||||
|
||||
_reader = channel.Reader;
|
||||
_writer = channel.Writer;
|
||||
|
||||
|
||||
@@ -18,5 +18,5 @@ namespace Ragon.Server.IO;
|
||||
|
||||
public interface IExecutor
|
||||
{
|
||||
public Task Run(Action action);
|
||||
public Task Run(Action action, TaskCreationOptions task = TaskCreationOptions.None);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Ragon.Server;
|
||||
|
||||
public class RagonContextObserver
|
||||
{
|
||||
private Dictionary<string, RagonContext> _contexts;
|
||||
public RagonContextObserver(Dictionary<string, RagonContext> contexts)
|
||||
{
|
||||
_contexts = contexts;
|
||||
}
|
||||
|
||||
public void OnAuthorized(RagonContext context)
|
||||
{
|
||||
_contexts.Add(context.LobbyPlayer.Id, context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Ragon.Server.IO;
|
||||
|
||||
namespace Ragon.Server;
|
||||
|
||||
public interface IRagonServer
|
||||
{
|
||||
RagonContext? ResolveContext(INetworkConnection connection);
|
||||
RagonContext? ResolveContext(string id);
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Ragon.Server.IO;
|
||||
|
||||
namespace Ragon.Server.Lobby;
|
||||
|
||||
public enum ConnectionStatus
|
||||
@@ -25,14 +27,16 @@ public enum ConnectionStatus
|
||||
|
||||
public class RagonLobbyPlayer
|
||||
{
|
||||
public INetworkConnection Connection { get; }
|
||||
public string Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string Payload { get; private set; }
|
||||
|
||||
public RagonLobbyPlayer(string id, string name, string payload)
|
||||
public RagonLobbyPlayer(INetworkConnection connection, string id, string name, string payload)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Payload = payload;
|
||||
Connection = connection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Ragon.Server.Entity;
|
||||
using Ragon.Server.IO;
|
||||
using Ragon.Server.Lobby;
|
||||
using Ragon.Server.Room;
|
||||
using Ragon.Server.Time;
|
||||
|
||||
namespace Ragon.Server.Plugin;
|
||||
|
||||
public class BaseRoomPlugin: IRoomPlugin
|
||||
{
|
||||
private IRagonRoom _ragonRoom;
|
||||
|
||||
public RagonRoomPlayer GetPlayerById(string id)
|
||||
{
|
||||
var player = _ragonRoom.GetPlayerById(id);
|
||||
return player;
|
||||
}
|
||||
|
||||
public RagonRoomPlayer GetPlayerByConnection(INetworkConnection connection)
|
||||
{
|
||||
var player = _ragonRoom.GetPlayerByConnection(connection);
|
||||
return player;
|
||||
}
|
||||
|
||||
public virtual void OnAttached(IRagonRoom room)
|
||||
{
|
||||
_ragonRoom = room;
|
||||
}
|
||||
|
||||
public virtual void OnDetached()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#region VIRTUAL
|
||||
|
||||
public virtual void Tick(float dt)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual bool OnEntityCreate(RagonRoomPlayer creator, RagonEntity entity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnEntityRemove(RagonRoomPlayer remover, RagonEntity entity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Ragon.Server.IO;
|
||||
using Ragon.Server.Lobby;
|
||||
using Ragon.Server.Room;
|
||||
|
||||
namespace Ragon.Server.Plugin;
|
||||
|
||||
public class BaseServerPlugin: IServerPlugin
|
||||
{
|
||||
private IRagonServer _ragonServer;
|
||||
|
||||
public RagonLobbyPlayer? GetPlayerById(string id)
|
||||
{
|
||||
var context = _ragonServer.ResolveContext(id);
|
||||
return context?.LobbyPlayer;
|
||||
}
|
||||
|
||||
public RagonLobbyPlayer? GetPlayerByConnection(INetworkConnection connection)
|
||||
{
|
||||
var context = _ragonServer.ResolveContext(connection);
|
||||
return context?.LobbyPlayer;
|
||||
}
|
||||
|
||||
public void OnAttached(IRagonServer server)
|
||||
{
|
||||
_ragonServer = server;
|
||||
}
|
||||
|
||||
public void OnDetached()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual bool OnRoomCreate(RagonLobbyPlayer player, RagonRoom room)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnRoomRemove(RagonLobbyPlayer player, RagonRoom room)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnRoomLeave(RagonRoomPlayer player, RagonRoom room)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnRoomJoin(RagonRoomPlayer player, RagonRoom room)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnCommand(string command, string payload)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public IRoomPlugin CreateRoomPlugin(RoomInformation information)
|
||||
{
|
||||
return new BaseRoomPlugin();
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace Ragon.Server.Plugin;
|
||||
public interface IRoomPlugin
|
||||
{
|
||||
void Tick(float dt);
|
||||
void OnAttached();
|
||||
void OnAttached(IRagonRoom room);
|
||||
void OnDetached();
|
||||
bool OnEntityCreate(RagonRoomPlayer creator, RagonEntity entity);
|
||||
bool OnEntityRemove(RagonRoomPlayer remover, RagonEntity entity);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using Ragon.Server.Http;
|
||||
using Ragon.Server.Lobby;
|
||||
using Ragon.Server.Room;
|
||||
|
||||
@@ -21,10 +22,12 @@ namespace Ragon.Server.Plugin;
|
||||
|
||||
public interface IServerPlugin
|
||||
{
|
||||
void OnAttached(IRagonServer server);
|
||||
void OnDetached();
|
||||
bool OnRoomCreate(RagonLobbyPlayer player, RagonRoom room);
|
||||
bool OnRoomRemove(RagonLobbyPlayer player, RagonRoom room);
|
||||
bool OnRoomLeave(RagonRoomPlayer player, RagonRoom room);
|
||||
bool OnRoomJoin(RagonRoomPlayer player, RagonRoom room);
|
||||
|
||||
bool OnCommand(string command, string payload);
|
||||
IRoomPlugin CreateRoomPlugin(RoomInformation information);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Ragon.Server.Room;
|
||||
|
||||
namespace Ragon.Server.Plugin.Web;
|
||||
|
||||
[Serializable]
|
||||
public class PlayerDto
|
||||
{
|
||||
public string Id { get; set;}
|
||||
public string Name { get; set; }
|
||||
|
||||
public PlayerDto(RagonRoomPlayer ragonRoomPlayer)
|
||||
{
|
||||
Id = ragonRoomPlayer.Id;
|
||||
Name = ragonRoomPlayer.Name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Ragon.Server.Room;
|
||||
|
||||
namespace Ragon.Server.Plugin.Web;
|
||||
|
||||
[Serializable]
|
||||
public class RoomDto
|
||||
{
|
||||
public string Id { get; set;}
|
||||
public int PlayerMin { get; set; }
|
||||
public int PlayerMax { get; set; }
|
||||
public int PlayerCount { get; set; }
|
||||
public PlayerDto[] Players { get; set; }
|
||||
|
||||
public RoomDto(RagonRoom room)
|
||||
{
|
||||
Id = room.Id;
|
||||
PlayerMin = room.PlayerMin;
|
||||
PlayerMax = room.PlayerMax;
|
||||
PlayerCount = room.PlayerCount;
|
||||
|
||||
Players = room.PlayerList.Select(p => new PlayerDto(p)).ToArray();
|
||||
}
|
||||
}
|
||||
+15
-8
@@ -8,14 +8,14 @@ using Ragon.Server.Room;
|
||||
|
||||
namespace Ragon.Server.Plugin.Web;
|
||||
|
||||
public class WebHookPlugin
|
||||
public class RagonWebHookPlugin
|
||||
{
|
||||
private Dictionary<string, string> _webHooks;
|
||||
|
||||
private RagonServer _server;
|
||||
private HttpClient _httpClient;
|
||||
|
||||
public WebHookPlugin(RagonServer server, Configuration configuration)
|
||||
public RagonWebHookPlugin(RagonServer server, Configuration configuration)
|
||||
{
|
||||
_webHooks = new Dictionary<string, string>(configuration.WebHooks);
|
||||
_httpClient = new HttpClient();
|
||||
@@ -30,7 +30,7 @@ public class WebHookPlugin
|
||||
var executor = context.Executor;
|
||||
executor.Run(async () =>
|
||||
{
|
||||
var authorizationOperation = (AuthorizationOperation) _server.Resolve(RagonOperation.AUTHORIZE);
|
||||
var authorizationOperation = (AuthorizationOperation) _server.ResolveOperation(RagonOperation.AUTHORIZE);
|
||||
var response = await _httpClient.PostAsync(new Uri(value), httpContent);
|
||||
if (response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
@@ -42,7 +42,7 @@ public class WebHookPlugin
|
||||
var authorizationResponse = JsonConvert.DeserializeObject<AuthorizationResponse>(content);
|
||||
if (authorizationResponse != null)
|
||||
{
|
||||
var lobbyPlayer = new RagonLobbyPlayer(authorizationResponse.Id, authorizationResponse.Name, authorizationResponse.Payload);
|
||||
var lobbyPlayer = new RagonLobbyPlayer(context.Connection, authorizationResponse.Id, authorizationResponse.Name, authorizationResponse.Payload);
|
||||
|
||||
context.SetPlayer(lobbyPlayer);
|
||||
authorizationOperation.Approve(context);
|
||||
@@ -58,12 +58,14 @@ public class WebHookPlugin
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RoomCreated(RagonContext context, RagonRoom room)
|
||||
public void RoomCreated(RagonContext context, RagonRoom room, RagonRoomPlayer player)
|
||||
{
|
||||
if (_webHooks.TryGetValue("room-created", out var value) && !string.IsNullOrEmpty(value))
|
||||
{
|
||||
var request = new RoomCreatedRequest()
|
||||
{
|
||||
Room = new RoomDto(room),
|
||||
Player = new PlayerDto(player)
|
||||
};
|
||||
var content = JsonContent.Create(request);
|
||||
var executor = context.Executor;
|
||||
@@ -75,8 +77,9 @@ public class WebHookPlugin
|
||||
{
|
||||
if (_webHooks.TryGetValue("room-removed", out var value) && !string.IsNullOrEmpty(value))
|
||||
{
|
||||
var request = new RoomCreatedRequest()
|
||||
var request = new RoomRemovedRequest()
|
||||
{
|
||||
Room = new RoomDto(ragonRoom)
|
||||
};
|
||||
var content = JsonContent.Create(request);
|
||||
var executor = context.Executor;
|
||||
@@ -88,8 +91,10 @@ public class WebHookPlugin
|
||||
{
|
||||
if (_webHooks.TryGetValue("room-joined", out var value) && !string.IsNullOrEmpty(value))
|
||||
{
|
||||
var request = new RoomCreatedRequest()
|
||||
var request = new RoomJoinedRequest()
|
||||
{
|
||||
Room = new RoomDto(existsRoom),
|
||||
Player = new PlayerDto(player)
|
||||
};
|
||||
var content = JsonContent.Create(request);
|
||||
var executor = context.Executor;
|
||||
@@ -101,8 +106,10 @@ public class WebHookPlugin
|
||||
{
|
||||
if (_webHooks.TryGetValue("room-leaved", out var value) && !string.IsNullOrEmpty(value))
|
||||
{
|
||||
var request = new RoomCreatedRequest()
|
||||
var request = new RoomLeavedRequest()
|
||||
{
|
||||
Room = new RoomDto(room),
|
||||
Player = new PlayerDto(roomPlayer)
|
||||
};
|
||||
var content = JsonContent.Create(request);
|
||||
var executor = context.Executor;
|
||||
@@ -1,7 +1,9 @@
|
||||
|
||||
namespace Ragon.Server.Plugin.Web;
|
||||
|
||||
[Serializable]
|
||||
public class RoomCreatedRequest
|
||||
{
|
||||
|
||||
public RoomDto Room { get; set; }
|
||||
public PlayerDto Player { get; set; }
|
||||
}
|
||||
@@ -2,5 +2,6 @@ namespace Ragon.Server.Plugin.Web;
|
||||
|
||||
public class RoomJoinedRequest
|
||||
{
|
||||
|
||||
public RoomDto Room { get; set; }
|
||||
public PlayerDto Player { get; set; }
|
||||
}
|
||||
@@ -3,5 +3,6 @@ namespace Ragon.Server.Plugin.Web;
|
||||
[Serializable]
|
||||
public class RoomLeavedRequest
|
||||
{
|
||||
|
||||
public RoomDto Room { get; set; }
|
||||
public PlayerDto Player { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using Ragon.Server.Plugin.Web;
|
||||
|
||||
namespace Ragon.Server.Plugin.Web;
|
||||
|
||||
[Serializable]
|
||||
public class RoomRemovedRequest
|
||||
{
|
||||
|
||||
public RoomDto Room { get; set; }
|
||||
}
|
||||
@@ -23,9 +23,8 @@ namespace Ragon.Server;
|
||||
|
||||
public class RagonContext
|
||||
{
|
||||
public INetworkConnection Connection { get; }
|
||||
public ConnectionStatus ConnectionStatus { get; set; }
|
||||
|
||||
public INetworkConnection Connection { get; }
|
||||
public IExecutor Executor { get; private set; }
|
||||
|
||||
public IRagonLobby Lobby { get; private set; }
|
||||
|
||||
@@ -18,6 +18,7 @@ using System.Diagnostics;
|
||||
using NLog;
|
||||
using Ragon.Protocol;
|
||||
using Ragon.Server.Handler;
|
||||
using Ragon.Server.Http;
|
||||
using Ragon.Server.IO;
|
||||
using Ragon.Server.Lobby;
|
||||
using Ragon.Server.Plugin;
|
||||
@@ -26,20 +27,23 @@ using Ragon.Server.Time;
|
||||
|
||||
namespace Ragon.Server;
|
||||
|
||||
public class RagonServer : INetworkListener
|
||||
public class RagonServer : IRagonServer, INetworkListener
|
||||
{
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly INetworkServer _server;
|
||||
private readonly IRagonOperation[] _handlers;
|
||||
private readonly IRagonLobby _lobby;
|
||||
private readonly IServerPlugin _serverPlugin;
|
||||
private readonly Thread _dedicatedThread;
|
||||
private readonly Executor _executor;
|
||||
private readonly WebHookPlugin _webhooks;
|
||||
private readonly Configuration _configuration;
|
||||
private readonly IRagonOperation[] _handlers;
|
||||
private readonly RagonWebHookPlugin _webhooks;
|
||||
private readonly RagonHttpServer _httpServer;
|
||||
private readonly RagonBuffer _reader;
|
||||
private readonly RagonBuffer _writer;
|
||||
private readonly IRagonLobby _lobby;
|
||||
private readonly RagonScheduler _scheduler;
|
||||
private readonly Dictionary<ushort, RagonContext> _contexts;
|
||||
private readonly Dictionary<ushort, RagonContext> _contextsByConnection;
|
||||
private readonly Dictionary<string, RagonContext> _contextsByPlayerId;
|
||||
private readonly Stopwatch _timer;
|
||||
private readonly long _tickRate = 0;
|
||||
|
||||
@@ -51,20 +55,26 @@ public class RagonServer : INetworkListener
|
||||
_server = server;
|
||||
_executor = _server.Executor;
|
||||
_configuration = configuration;
|
||||
_contexts = new Dictionary<ushort, RagonContext>();
|
||||
_serverPlugin = plugin;
|
||||
_contextsByConnection = new Dictionary<ushort, RagonContext>();
|
||||
_contextsByPlayerId = new Dictionary<string, RagonContext>();
|
||||
_lobby = new LobbyInMemory();
|
||||
_scheduler = new RagonScheduler();
|
||||
_webhooks = new WebHookPlugin(this, configuration);
|
||||
_webhooks = new RagonWebHookPlugin(this, configuration);
|
||||
_dedicatedThread = new Thread(Execute);
|
||||
_dedicatedThread.IsBackground = true;
|
||||
|
||||
_httpServer = new RagonHttpServer(_executor, plugin);
|
||||
_reader = new RagonBuffer();
|
||||
_writer = new RagonBuffer();
|
||||
_tickRate = 1000 / _configuration.ServerTickRate;
|
||||
_timer = new Stopwatch();
|
||||
|
||||
var contextObserver = new RagonContextObserver(_contextsByPlayerId);
|
||||
|
||||
_serverPlugin.OnAttached(this);
|
||||
|
||||
_handlers = new IRagonOperation[byte.MaxValue];
|
||||
_handlers[(byte) RagonOperation.AUTHORIZE] = new AuthorizationOperation(_webhooks, _writer, configuration);
|
||||
_handlers[(byte) RagonOperation.AUTHORIZE] = new AuthorizationOperation(_webhooks, contextObserver, _writer, configuration);
|
||||
_handlers[(byte) RagonOperation.JOIN_OR_CREATE_ROOM] = new RoomJoinOrCreateOperation(plugin, _webhooks);
|
||||
_handlers[(byte) RagonOperation.CREATE_ROOM] = new RoomCreateOperation(plugin, _webhooks);
|
||||
_handlers[(byte) RagonOperation.JOIN_ROOM] = new RoomJoinOperation(plugin, _webhooks);
|
||||
@@ -79,8 +89,6 @@ public class RagonServer : INetworkListener
|
||||
_logger.Trace($"Server Tick Rate: {_configuration.ServerTickRate}");
|
||||
}
|
||||
|
||||
public IRagonOperation Resolve(RagonOperation operation) => _handlers[(byte)operation];
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
_timer.Start();
|
||||
@@ -88,11 +96,11 @@ public class RagonServer : INetworkListener
|
||||
{
|
||||
if (_timer.ElapsedMilliseconds > _tickRate)
|
||||
{
|
||||
_executor.Update();
|
||||
_scheduler.Update(_timer.ElapsedMilliseconds / 1000.0f);
|
||||
_timer.Restart();
|
||||
}
|
||||
|
||||
_executor.Update();
|
||||
_server.Update();
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
@@ -108,6 +116,7 @@ public class RagonServer : INetworkListener
|
||||
Port = _configuration.Port,
|
||||
};
|
||||
|
||||
_httpServer.Start(_configuration);
|
||||
_server.Start(this, networkConfiguration);
|
||||
|
||||
if (executeInDedicatedThread)
|
||||
@@ -118,6 +127,7 @@ public class RagonServer : INetworkListener
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_serverPlugin.OnDetached();
|
||||
_server.Stop();
|
||||
_dedicatedThread.Interrupt();
|
||||
}
|
||||
@@ -127,12 +137,12 @@ public class RagonServer : INetworkListener
|
||||
var context = new RagonContext(connection, _executor, _lobby, _scheduler);
|
||||
|
||||
_logger.Trace($"Connected: {connection.Id}");
|
||||
_contexts.Add(connection.Id, context);
|
||||
_contextsByConnection.Add(connection.Id, context);
|
||||
}
|
||||
|
||||
public void OnDisconnected(INetworkConnection connection)
|
||||
{
|
||||
if (_contexts.Remove(connection.Id, out var context))
|
||||
if (_contextsByConnection.Remove(connection.Id, out var context))
|
||||
{
|
||||
var room = context.Room;
|
||||
if (room != null)
|
||||
@@ -152,7 +162,7 @@ public class RagonServer : INetworkListener
|
||||
|
||||
public void OnTimeout(INetworkConnection connection)
|
||||
{
|
||||
if (_contexts.Remove(connection.Id, out var context))
|
||||
if (_contextsByConnection.Remove(connection.Id, out var context))
|
||||
{
|
||||
var room = context.Room;
|
||||
if (room != null)
|
||||
@@ -173,7 +183,7 @@ public class RagonServer : INetworkListener
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_contexts.TryGetValue(connection.Id, out var context))
|
||||
if (_contextsByConnection.TryGetValue(connection.Id, out var context))
|
||||
{
|
||||
_writer.Clear();
|
||||
_reader.Clear();
|
||||
@@ -188,4 +198,7 @@ public class RagonServer : INetworkListener
|
||||
_logger.Error(ex);
|
||||
}
|
||||
}
|
||||
public IRagonOperation ResolveOperation(RagonOperation operation) => _handlers[(byte)operation];
|
||||
public RagonContext? ResolveContext(INetworkConnection connection) => _contextsByConnection.TryGetValue(connection.Id, out var context) ? context : null;
|
||||
public RagonContext? ResolveContext(string playerId) => _contextsByPlayerId.TryGetValue(playerId, out var context) ? context : null;
|
||||
}
|
||||
@@ -38,6 +38,8 @@ public struct Configuration
|
||||
public ushort ServerTickRate;
|
||||
public string GameProtocol;
|
||||
public ushort Port;
|
||||
public ushort HttpPort;
|
||||
public string HttpKey;
|
||||
public int LimitConnections;
|
||||
public int LimitPlayersPerRoom;
|
||||
public int LimitRooms;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Ragon.Server.IO;
|
||||
|
||||
namespace Ragon.Server.Room;
|
||||
|
||||
public interface IRagonRoom
|
||||
{
|
||||
RagonRoomPlayer GetPlayerByConnection(INetworkConnection connection);
|
||||
RagonRoomPlayer GetPlayerById(string id);
|
||||
}
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
using Ragon.Protocol;
|
||||
using Ragon.Server.Entity;
|
||||
using Ragon.Server.IO;
|
||||
using Ragon.Server.Plugin;
|
||||
using Ragon.Server.Time;
|
||||
|
||||
namespace Ragon.Server.Room;
|
||||
|
||||
public class RagonRoom : IRagonAction
|
||||
public class RagonRoom : IRagonRoom, IRagonAction
|
||||
{
|
||||
public string Id { get; private set; }
|
||||
public string Map { get; private set; }
|
||||
@@ -204,4 +205,7 @@ public class RagonRoom : IRagonAction
|
||||
foreach (var readyPlayer in ReadyPlayersList)
|
||||
readyPlayer.Connection.Reliable.Send(data);
|
||||
}
|
||||
|
||||
public RagonRoomPlayer GetPlayerByConnection(INetworkConnection connection) => Players[connection.Id];
|
||||
public RagonRoomPlayer GetPlayerById(string id) => PlayerList.First(p => p.Id == id);
|
||||
}
|
||||
Reference in New Issue
Block a user