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

View File

@ -8,4 +8,10 @@ ServerDomains = []
PluginsDirPath = "" PluginsDirPath = ""
# ID of this server in terms of Cadmium federation network. WARNING! This ID should be maximally unique. # 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;
using Zirconium.Core.Modules.Interfaces; using Zirconium.Core.Modules.Interfaces;
using Zirconium.Core.Logging; using Zirconium.Core.Logging;
using WebSocketSharp.Server;
namespace Zirconium.Core namespace Zirconium.Core
{ {
@ -12,15 +13,28 @@ namespace Zirconium.Core
public ModuleManager ModuleManager { get; } public ModuleManager ModuleManager { get; }
public IHostModuleAPI HostModuleAPI { get; } public IHostModuleAPI HostModuleAPI { get; }
public AuthManager AuthManager { get; } public AuthManager AuthManager { get; }
private WebSocketServer _websocketServer;
public App(Config config) public App(Config config)
{ {
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(); SessionManager = new SessionManager();
Router = new Router(this); Router = new Router(this);
HostModuleAPI = new HostModuleAPI(this, Router); HostModuleAPI = new HostModuleAPI(this, Router);
AuthManager = new AuthManager(this); AuthManager = new AuthManager(this);
Log.Info("Zirconium is initialized successfully"); 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 public class Config
{ {
// A list of enabled plugins (or extensions) in server // 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) // Server domain names (e.g. example.com)
public string[] ServerDomains {get; set;} public string[] ServerDomains { get; set; }
// Path to directory with plugin assemblies // 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 // 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;
using System.Threading.Tasks;
using WebSocketSharp.Server; using WebSocketSharp.Server;
using WebSocketSharp; using WebSocketSharp;
using Zirconium.Core.Models; using Zirconium.Core.Models;
using Zirconium.Utils; using Zirconium.Utils;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Zirconium.Core namespace Zirconium.Core
{ {
@ -19,18 +21,49 @@ namespace Zirconium.Core
protected override void OnClose(CloseEventArgs e) protected override void OnClose(CloseEventArgs e)
{ {
_app.SessionManager.DeleteSession(ID); _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 // TODO implement closing connection
} }
protected override void OnError(ErrorEventArgs e) 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) 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() protected override void OnOpen()
@ -40,12 +73,12 @@ namespace Zirconium.Core
connInfo.ClientAddress = ip; connInfo.ClientAddress = ip;
connInfo.ConnectionHandler = this; connInfo.ConnectionHandler = this;
_app.SessionManager.AddSession(ID, connInfo); _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) { public void SendMessage(string message)
this.Send(message.ToByteArray()); {
return Task.CompletedTask; this.Send(message);
} }
} }
} }

View File

@ -12,6 +12,8 @@ namespace Zirconium.Core
} }
class Program class Program
{ {
private static bool keepRunning = true;
static void Main(string[] args) static void Main(string[] args)
{ {
string configPath = null; string configPath = null;
@ -38,6 +40,14 @@ namespace Zirconium.Core
Log.Fatal($"Error occured when parsing config - {e.Message}"); Log.Fatal($"Error occured when parsing config - {e.Message}");
} }
App app = new App(config); 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")] [JsonProperty("type")]
public string MessageType { get; set; } public string MessageType { get; set; }
[JsonProperty("from")] [JsonProperty("from", NullValueHandling = NullValueHandling.Ignore)]
public string From { get; set; } public string From { get; set; }
[JsonProperty("to")] [JsonProperty("to", NullValueHandling = NullValueHandling.Ignore)]
public string To { get; set; } public string To { get; set; }
[JsonProperty("ok")] [JsonProperty("ok")]
public bool Ok { get; set; } public bool Ok { get; set; }
[JsonProperty("authToken")] [JsonProperty("authToken", NullValueHandling = NullValueHandling.Ignore)]
public string AuthToken { get; set; } public string AuthToken { get; set; }
[JsonProperty("payload")] [JsonProperty("payload")]
@ -30,22 +30,25 @@ namespace Zirconium.Core.Models
public BaseMessage(BaseMessage message, bool reply) public BaseMessage(BaseMessage message, bool reply)
{ {
ID = message.ID; if (message != null)
MessageType = message.MessageType;
if (reply)
{ {
From = message.To; ID = message.ID;
To = message.From; MessageType = message.MessageType;
} if (reply)
else {
{ From = message.To;
From = message.From; To = message.From;
To = message.To; }
} else
{
From = message.From;
To = message.To;
}
Ok = message.Ok; Ok = message.Ok;
AuthToken = message.AuthToken; AuthToken = message.AuthToken;
Payload = message.Payload; Payload = message.Payload;
}
} }
} }
} }

View File

@ -25,18 +25,18 @@ namespace Zirconium.Core
public void RouteMessage(ConnectionInfo connInfo, BaseMessage message) public void RouteMessage(ConnectionInfo connInfo, BaseMessage message)
{ {
var handlers = _c2sMessageHandlers[message.MessageType]; var handlers = _c2sMessageHandlers.GetValueOrDefault(message.MessageType, null);
if (handlers == null) if (handlers == null)
{ {
Log.Warning($"Drop message with type {message.MessageType} because server hasn't proper handlers"); Log.Warning($"Drop message with type \"{message.MessageType}\" because server hasn't proper handlers");
var serializedMsg = JsonConvert.SerializeObject( var msg = OtherUtils.GenerateProtocolError(
OtherUtils.GenerateProtocolError( message,
message, "unhandled",
"unhandled", $"Server doesn't implement message type \"{message.MessageType}\"",
$"Server doesn't implement message type {message.MessageType}", new Dictionary<string, object>()
new Dictionary<string, object>()
)
); );
msg.From = _app.Config.ServerID;
var serializedMsg = JsonConvert.SerializeObject(msg);
connInfo.ConnectionHandler.SendMessage(serializedMsg); connInfo.ConnectionHandler.SendMessage(serializedMsg);
return; return;
} }
@ -113,7 +113,8 @@ namespace Zirconium.Core
public void RemoveC2SHandler(string messageType, IC2SMessageHandler handler) 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"); 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) 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"); 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 System.Collections.Generic;
using Zirconium.Core.Models; using Zirconium.Core.Models;
@ -13,6 +14,9 @@ namespace Zirconium.Utils
err.ErrPayload = errPayload; err.ErrPayload = errPayload;
BaseMessage msg = new BaseMessage(parentMessage, true); BaseMessage msg = new BaseMessage(parentMessage, true);
if (parentMessage == null) {
msg.ID = Guid.NewGuid().ToString();
}
msg.Ok = false; msg.Ok = false;
msg.Payload = err.ToDictionary(); msg.Payload = err.ToDictionary();
return msg; return msg;