Implement message/core event routing (with pluggable handlers)

This commit is contained in:
ChronosX88 2020-06-26 22:59:53 +04:00
parent 3a54c18af6
commit fc609869eb
6 changed files with 123 additions and 6 deletions

View File

@ -1,5 +1,6 @@
using Zirconium.Core.Modules; using Zirconium.Core.Modules;
using Zirconium.Core.Modules.Interfaces; using Zirconium.Core.Modules.Interfaces;
using Zirconium.Core.Logging;
namespace Zirconium.Core namespace Zirconium.Core
{ {
@ -9,12 +10,15 @@ namespace Zirconium.Core
public Router Router { get; } public Router Router { get; }
public ModuleManager ModuleManager { get; } public ModuleManager ModuleManager { get; }
public IHostModuleAPI HostModuleAPI { get; } public IHostModuleAPI HostModuleAPI { get; }
public AuthManager AuthManager { get; }
public App() public App()
{ {
SessionManager = new SessionManager(); SessionManager = new SessionManager();
Router = new Router(this); Router = new Router(this);
HostModuleAPI = new HostModuleAPI(Router); HostModuleAPI = new HostModuleAPI(Router);
AuthManager = new AuthManager(this);
Log.Info("Zirconium is initialized successfully");
} }
} }
} }

View File

@ -2,6 +2,7 @@ using System;
using WebSocketSharp.Server; using WebSocketSharp.Server;
using WebSocketSharp; using WebSocketSharp;
using Zirconium.Core.Models; using Zirconium.Core.Models;
using Zirconium.Utils;
namespace Zirconium.Core namespace Zirconium.Core
{ {
@ -36,9 +37,14 @@ namespace Zirconium.Core
var ip = Context.UserEndPoint.Address; var ip = Context.UserEndPoint.Address;
var connInfo = new ConnectionInfo(); var connInfo = new ConnectionInfo();
connInfo.ClientAddress = ip; connInfo.ClientAddress = ip;
connInfo.ConnectionHandler = this;
_app.SessionManager.AddSession(ID, connInfo); _app.SessionManager.AddSession(ID, connInfo);
Console.WriteLine($"Connection {ID} was created"); // TODO implement normal logging Console.WriteLine($"Connection {ID} was created"); // TODO implement normal logging
} }
public void SendMessage(string message) {
this.Send(message.ToByteArray());
}
} }
} }

View File

@ -6,7 +6,7 @@ namespace Zirconium.Core
{ {
static void Main(string[] args) static void Main(string[] args)
{ {
Console.WriteLine("Hello World! Zirconium"); App app = new App();
} }
} }
} }

View File

@ -7,5 +7,6 @@ namespace Zirconium.Core.Models
public string LastTokenHash { get; set; } public string LastTokenHash { get; set; }
public JWTPayload LastTokenPayload { get; set; } public JWTPayload LastTokenPayload { get; set; }
public IPAddress ClientAddress { get; set; } public IPAddress ClientAddress { get; set; }
public ConnectionHandler ConnectionHandler { get; set; }
} }
} }

View File

@ -1,7 +1,12 @@
using System.Threading.Tasks;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Zirconium.Core.Models; using Zirconium.Core.Models;
using Zirconium.Core.Modules.Interfaces; using Zirconium.Core.Modules.Interfaces;
using Zirconium.Utils; using Zirconium.Utils;
using Zirconium.Core.Logging;
using Newtonsoft.Json;
using System.Security.Cryptography;
namespace Zirconium.Core namespace Zirconium.Core
{ {
@ -18,19 +23,99 @@ namespace Zirconium.Core
_coreEventsHandlers = new Dictionary<string, List<ICoreEventHandler>>(); _coreEventsHandlers = new Dictionary<string, List<ICoreEventHandler>>();
} }
public void RouteMessage(ConnectionInfo connInfo, BaseMessage message) { public void RouteMessage(ConnectionInfo connInfo, BaseMessage message)
{
var handlers = _c2sMessageHandlers[message.MessageType];
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>()
)
);
connInfo.ConnectionHandler.SendMessage(serializedMsg);
return;
}
foreach (var h in handlers)
{
if (h.IsAuthorizationRequired())
{
JWTPayload tokenPayload;
try
{
tokenPayload = _app.AuthManager.ValidateToken(message.AuthToken);
}
catch (Exception e)
{
Log.Warning(e.Message);
var serializedMsg = JsonConvert.SerializeObject(
OtherUtils.GenerateProtocolError(
message,
"unauthorized",
"Unauthorized access",
new Dictionary<string, object>()
)
);
connInfo.ConnectionHandler.SendMessage(serializedMsg);
return;
} }
public void AddC2SHandler(string messageType, IC2SMessageHandler handler) { if (connInfo.LastTokenHash == "" || connInfo.LastTokenHash == null)
if (_c2sMessageHandlers.GetValueOrDefault(messageType, null) == null) { {
string hash;
using (SHA512 shaM = new SHA512Managed())
{
hash = shaM.ComputeHash(message.AuthToken.ToByteArray()).ConvertToString();
}
connInfo.LastTokenHash = hash;
// TODO implement comparing last token hash and if hash isn't changed then check payload
// if payload already exists - then skip validating auth token
}
connInfo.LastTokenPayload = tokenPayload;
}
Task.Run(() =>
{
// probably need to wrap whole foreach body, not only HandleMessage call - need to investigate
h.HandleMessage(message);
});
}
}
public void RouteCoreEvent(CoreEvent coreEvent)
{
var handlers = _coreEventsHandlers[coreEvent.Name];
if (handlers == null) {
Log.Warning($"Drop core event {coreEvent.Name} because server hasn't proper handlers");
return;
}
foreach (var h in handlers) {
Task.Run(() =>
{
h.HandleEvent(coreEvent);
});
}
}
public void AddC2SHandler(string messageType, IC2SMessageHandler handler)
{
if (_c2sMessageHandlers.GetValueOrDefault(messageType, null) == null)
{
_c2sMessageHandlers[messageType] = new List<IC2SMessageHandler>(); _c2sMessageHandlers[messageType] = new List<IC2SMessageHandler>();
} }
this._c2sMessageHandlers[messageType].Add(handler); this._c2sMessageHandlers[messageType].Add(handler);
} }
public void AddCoreEventHandler(string eventType, ICoreEventHandler handler) { public void AddCoreEventHandler(string eventType, ICoreEventHandler handler)
if (_coreEventsHandlers.GetValueOrDefault(eventType, null) == null) { {
if (_coreEventsHandlers.GetValueOrDefault(eventType, null) == null)
{
_coreEventsHandlers[eventType] = new List<ICoreEventHandler>(); _coreEventsHandlers[eventType] = new List<ICoreEventHandler>();
} }
this._coreEventsHandlers[eventType].Add(handler); this._coreEventsHandlers[eventType].Add(handler);

View File

@ -0,0 +1,21 @@
using System.Collections.Generic;
using Zirconium.Core.Models;
namespace Zirconium.Utils
{
public static class OtherUtils
{
public static BaseMessage GenerateProtocolError(BaseMessage parentMessage, string errCode, string errText, IDictionary<string, object> errPayload)
{
ProtocolError err = new ProtocolError();
err.ErrCode = errCode;
err.ErrText = errText;
err.ErrPayload = errPayload;
BaseMessage msg = new BaseMessage(parentMessage, true);
msg.Ok = false;
msg.Payload = err.ToDictionary();
return msg;
}
}
}