ln.application/ApplicationWebSocket.cs

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);
}
}
}