Implement running websocket server and add handling messages in ConnectionHandler

This commit is contained in:
ChronosX88 2020-07-16 12:47:18 +04:00
parent f34b4e3596
commit 394f9ab908
9 changed files with 125 additions and 43 deletions

4
.vscode/launch.json vendored
View File

@ -11,11 +11,11 @@
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/src/Zirconium/bin/Debug/netcoreapp3.1/Zirconium.dll",
"args": [],
"args": ["--config", "${workspaceFolder}/.config.toml"],
"cwd": "${workspaceFolder}/src/Zirconium",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
"stopAtEntry": false,
},
{
"name": ".NET Core Attach",

View File

@ -8,4 +8,10 @@ ServerDomains = []
PluginsDirPath = ""
# ID of this server in terms of Cadmium federation network. WARNING! This ID should be maximally unique.
ServerID = ""
ServerID = ""
# Websocket server settings
[Websocket]
Host = "localhost"
Port = 8000
Endpoint = ""

View File

@ -1,6 +1,7 @@
using Zirconium.Core.Modules;
using Zirconium.Core.Modules.Interfaces;
using Zirconium.Core.Logging;
using WebSocketSharp.Server;
namespace Zirconium.Core
{
@ -12,15 +13,28 @@ namespace Zirconium.Core
public ModuleManager ModuleManager { get; }
public IHostModuleAPI HostModuleAPI { get; }
public AuthManager AuthManager { get; }
private WebSocketServer _websocketServer;
public App(Config config)
{
Config = config;
_websocketServer = new WebSocketServer($"ws://{config.Websocket.Host}:{config.Websocket.Port}");
_websocketServer.AddWebSocketService<ConnectionHandler>(config.Websocket.Endpoint, () => new ConnectionHandler(this));
SessionManager = new SessionManager();
Router = new Router(this);
HostModuleAPI = new HostModuleAPI(this, Router);
AuthManager = new AuthManager(this);
Log.Info("Zirconium is initialized successfully");
}
public void Run()
{
_websocketServer.Start();
}
public void Destroy() {
Log.Info("Shutting down Zirconium...");
_websocketServer.Stop();
}
}
}

View File

@ -3,15 +3,25 @@ namespace Zirconium.Core
public class Config
{
// A list of enabled plugins (or extensions) in server
public string[] EnabledPlugins {get; set;}
public string[] EnabledPlugins { get; set; }
// Server domain names (e.g. example.com)
public string[] ServerDomains {get; set;}
public string[] ServerDomains { get; set; }
// Path to directory with plugin assemblies
public string PluginsDirPath {get; set;}
public string PluginsDirPath { get; set; }
// ID of this server in terms of Cadmium federation network
public string ServerID {get; set;}
public string ServerID { get; set; }
// Websocket server settings
public Websocket Websocket { get; set; }
}
public class Websocket
{
public string Host { get; set; }
public int Port { get; set; }
public string Endpoint { get; set; }
}
}

View File

@ -1,9 +1,11 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using WebSocketSharp.Server;
using WebSocketSharp;
using Zirconium.Core.Models;
using Zirconium.Utils;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Zirconium.Core
{
@ -19,18 +21,49 @@ namespace Zirconium.Core
protected override void OnClose(CloseEventArgs e)
{
_app.SessionManager.DeleteSession(ID);
Console.WriteLine($"Connection {ID} was closed (reason: {e.Reason})"); // TODO implement normal logging
Logging.Log.Info($"Connection {ID} was closed (reason: {e.Reason})");
// TODO implement closing connection
}
protected override void OnError(ErrorEventArgs e)
{
Console.WriteLine($"Error occurred: {e.Exception}"); // TODO implement normal logging
Logging.Log.Error($"Error occurred: {e.Exception}");
}
protected override void OnMessage(MessageEventArgs e)
{
// TODO implement message parsing and routing
try
{
if (e.IsText)
{
var msg = JsonConvert.DeserializeObject<BaseMessage>(e.Data);
_app.Router.RouteMessage(_app.SessionManager.GetConnectionInfo(ID), msg);
}
else
{
var errMsg = OtherUtils.GenerateProtocolError(
null,
"parseError",
$"Server cannot parse this message yet because it is not JSON",
new Dictionary<string, object>()
);
errMsg.From = _app.Config.ServerID;
var msgStr = JsonConvert.SerializeObject(errMsg);
this.SendMessage(msgStr);
}
}
catch (Exception ex)
{
var errMsg = OtherUtils.GenerateProtocolError(
null,
"parseError",
$"Server cannot parse this message! {ex.Message}",
new Dictionary<string, object>()
);
errMsg.From = _app.Config.ServerID;
var msgStr = JsonConvert.SerializeObject(errMsg);
this.SendMessage(msgStr);
}
}
protected override void OnOpen()
@ -40,12 +73,12 @@ namespace Zirconium.Core
connInfo.ClientAddress = ip;
connInfo.ConnectionHandler = this;
_app.SessionManager.AddSession(ID, connInfo);
Console.WriteLine($"Connection {ID} was created"); // TODO implement normal logging
Logging.Log.Info($"Connection {ID} was created");
}
public Task SendMessage(string message) {
this.Send(message.ToByteArray());
return Task.CompletedTask;
public void SendMessage(string message)
{
this.Send(message);
}
}
}

View File

@ -12,6 +12,8 @@ namespace Zirconium.Core
}
class Program
{
private static bool keepRunning = true;
static void Main(string[] args)
{
string configPath = null;
@ -38,6 +40,14 @@ namespace Zirconium.Core
Log.Fatal($"Error occured when parsing config - {e.Message}");
}
App app = new App(config);
app.Run();
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
app.Destroy();
keepRunning = false;
};
while(keepRunning) {}
}
}
}

View File

@ -11,16 +11,16 @@ namespace Zirconium.Core.Models
[JsonProperty("type")]
public string MessageType { get; set; }
[JsonProperty("from")]
[JsonProperty("from", NullValueHandling = NullValueHandling.Ignore)]
public string From { get; set; }
[JsonProperty("to")]
[JsonProperty("to", NullValueHandling = NullValueHandling.Ignore)]
public string To { get; set; }
[JsonProperty("ok")]
public bool Ok { get; set; }
[JsonProperty("authToken")]
[JsonProperty("authToken", NullValueHandling = NullValueHandling.Ignore)]
public string AuthToken { get; set; }
[JsonProperty("payload")]
@ -30,22 +30,25 @@ namespace Zirconium.Core.Models
public BaseMessage(BaseMessage message, bool reply)
{
ID = message.ID;
MessageType = message.MessageType;
if (reply)
if (message != null)
{
From = message.To;
To = message.From;
}
else
{
From = message.From;
To = message.To;
}
ID = message.ID;
MessageType = message.MessageType;
if (reply)
{
From = message.To;
To = message.From;
}
else
{
From = message.From;
To = message.To;
}
Ok = message.Ok;
AuthToken = message.AuthToken;
Payload = message.Payload;
Ok = message.Ok;
AuthToken = message.AuthToken;
Payload = message.Payload;
}
}
}
}

View File

@ -25,18 +25,18 @@ namespace Zirconium.Core
public void RouteMessage(ConnectionInfo connInfo, BaseMessage message)
{
var handlers = _c2sMessageHandlers[message.MessageType];
var handlers = _c2sMessageHandlers.GetValueOrDefault(message.MessageType, null);
if (handlers == null)
{
Log.Warning($"Drop message with type {message.MessageType} because server hasn't proper handlers");
var serializedMsg = JsonConvert.SerializeObject(
OtherUtils.GenerateProtocolError(
message,
"unhandled",
$"Server doesn't implement message type {message.MessageType}",
new Dictionary<string, object>()
)
Log.Warning($"Drop message with type \"{message.MessageType}\" because server hasn't proper handlers");
var msg = OtherUtils.GenerateProtocolError(
message,
"unhandled",
$"Server doesn't implement message type \"{message.MessageType}\"",
new Dictionary<string, object>()
);
msg.From = _app.Config.ServerID;
var serializedMsg = JsonConvert.SerializeObject(msg);
connInfo.ConnectionHandler.SendMessage(serializedMsg);
return;
}
@ -113,7 +113,8 @@ namespace Zirconium.Core
public void RemoveC2SHandler(string messageType, IC2SMessageHandler handler)
{
if (!this._c2sMessageHandlers[messageType].Remove(handler)) {
if (!this._c2sMessageHandlers[messageType].Remove(handler))
{
Log.Warning("attempt to remove c2s handler which doesn't exist in router");
}
}
@ -129,7 +130,8 @@ namespace Zirconium.Core
public void RemoveCoreEventHandler(string eventType, ICoreEventHandler handler)
{
if (!this._coreEventsHandlers[eventType].Remove(handler)) {
if (!this._coreEventsHandlers[eventType].Remove(handler))
{
Log.Warning("attempt to remove core handler which doesn't exist in router");
}
}

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Zirconium.Core.Models;
@ -13,6 +14,9 @@ namespace Zirconium.Utils
err.ErrPayload = errPayload;
BaseMessage msg = new BaseMessage(parentMessage, true);
if (parentMessage == null) {
msg.ID = Guid.NewGuid().ToString();
}
msg.Ok = false;
msg.Payload = err.ToDictionary();
return msg;