165 lines
6.1 KiB
C#
165 lines
6.1 KiB
C#
using System;
|
|
using ln.http.websocket;
|
|
using ln.json;
|
|
using ln.logging;
|
|
using ln.types.rpc;
|
|
using ln.http;
|
|
using System.Collections.Generic;
|
|
using ln.application.slots;
|
|
using ln.json.mapping;
|
|
using ln.identities;
|
|
using ln.application.messages;
|
|
using ln.http.resources;
|
|
namespace ln.application
|
|
{
|
|
public class ApplicationWebSocket : WebSocket
|
|
{
|
|
static Dictionary<string, Func<JSONValue, object>> messageConverters = new Dictionary<string, Func<JSONValue, object>>();
|
|
static public void RegisterMessageConverter(string messageType, Func<JSONValue, object> converter) => messageConverters[messageType] = converter;
|
|
static public Func<JSONValue, object> FindConverter(string messageType) => messageConverters[messageType];
|
|
|
|
public Application Application { get; }
|
|
public ApplicationSession ApplicationSession => (Hello != null) ? Application.GetApplicationSession(Hello.ApplicationSessionID) : null;
|
|
|
|
public WSHello Hello { get; set; }
|
|
|
|
static ApplicationWebSocket()
|
|
{
|
|
RegisterMessageConverter("WSHello", (JSONValue json) => JSONMapper.DefaultMapper.FromJson(json, typeof(WSHello)));
|
|
RegisterMessageConverter("RPCCall", (JSONValue json) => JSONMapper.DefaultMapper.FromJson(json, typeof(RPCCall)));
|
|
RegisterMessageConverter("SlotRequest", (JSONValue json) => JSONMapper.DefaultMapper.FromJson(json, typeof(SlotRequest)));
|
|
RegisterMessageConverter("AuthenticationProve", (JSONValue json) => JSONMapper.DefaultMapper.FromJson(json, typeof(AuthenticationProve)));
|
|
RegisterMessageConverter("AuthenticationRequest", (JSONValue json) => JSONMapper.DefaultMapper.FromJson(json, typeof(AuthenticationRequest)));
|
|
}
|
|
|
|
|
|
public ApplicationWebSocket(Application application, HttpRequest httpRequest)
|
|
: base(httpRequest)
|
|
{
|
|
Application = application;
|
|
}
|
|
|
|
public override bool Received(string textMessage)
|
|
{
|
|
JSONObject json = (JSONObject)JSONParser.Parse(textMessage);
|
|
|
|
if (!json.ContainsKey("id"))
|
|
{
|
|
Logging.Log(LogLevel.WARNING, "ApplicatioNWebSocket received json message without id");
|
|
return false;
|
|
}
|
|
|
|
long messageID = (long)json["id"].ToNative();
|
|
|
|
if (!json.ContainsKey("type"))
|
|
{
|
|
SendError(messageID, "type missing", "ApplicationWebSocket received message without 'type' attribute");
|
|
return false;
|
|
}
|
|
|
|
string messageType = json["type"].ToNative() as string;
|
|
JSONValue message = json.ContainsKey("message") ? json["message"] : JSONNull.Instance;
|
|
|
|
return ReceivedMessage(messageID,messageType,message);
|
|
}
|
|
|
|
public virtual bool ReceivedMessage(long messageId,string messageType,JSONValue message)
|
|
{
|
|
try
|
|
{
|
|
object convertedMessage = FindConverter(messageType)(message);
|
|
ReceivedMessage(messageId, messageType, convertedMessage);
|
|
|
|
return true;
|
|
} catch (Exception e)
|
|
{
|
|
Logging.Log(e);
|
|
SendError(messageId, e.ToString(), e.InnerException?.ToString());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public virtual void ReceivedMessage(long messageId, string messageType, object message)
|
|
{
|
|
ApplicationSession.SetCurrentSession(ApplicationSession);
|
|
|
|
try
|
|
{
|
|
object result;
|
|
|
|
if (message is WSHello hello)
|
|
{
|
|
if (Hello == null)
|
|
{
|
|
Hello = hello;
|
|
hello.ApplicationSessionID = ApplicationSession.SessionID;
|
|
|
|
result = hello;
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException("WSHello already received!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = ApplicationSession?.ProcessMessage(message);
|
|
if (result is null)
|
|
{
|
|
result = Application.ProcessMessage(message);
|
|
}
|
|
if (result is null)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
SendMessage(messageId, result);
|
|
} catch (Exception e)
|
|
{
|
|
SendError(messageId, e.ToString(), e.InnerException?.ToString());
|
|
}
|
|
finally
|
|
{
|
|
ApplicationSession.ClearCurrentSession();
|
|
}
|
|
}
|
|
|
|
public override bool Received(byte[] binaryMessage)
|
|
{
|
|
return base.Received(binaryMessage);
|
|
}
|
|
|
|
public void SendMessage(long messageID, object message)
|
|
{
|
|
string messageType = message.GetType().Name;
|
|
JSONObject jsonMessage = message is JSONObject ? message as JSONObject : JSONObject.From(message);
|
|
|
|
SendMessage(messageID, messageType, jsonMessage);
|
|
}
|
|
public virtual void SendMessage(long messageID,string messageType,JSONObject message)
|
|
{
|
|
JSONObject messageFrame = new JSONObject();
|
|
messageFrame["id"] = new JSONNumber(messageID);
|
|
messageFrame["type"] = new JSONString(messageType);
|
|
messageFrame["message"] = message;
|
|
|
|
Send(messageFrame.ToString());
|
|
}
|
|
|
|
public virtual void SendError(long messageId, string error, string cause) => SendError(messageId, error, cause, null);
|
|
public virtual void SendError(long messageId, string error,string cause,JSONValue details)
|
|
{
|
|
JSONObject failed = new JSONObject();
|
|
failed["message"] = new JSONString(error);
|
|
failed["cause"] = new JSONString(cause);
|
|
failed["details"] = details;
|
|
|
|
Logging.Log(LogLevel.WARNING, "ApplicationWebSocket sends error: {0}\n{1}",error,cause);
|
|
SendMessage(messageId, "error", failed);
|
|
}
|
|
|
|
}
|
|
|
|
}
|