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> messageConverters = new Dictionary>(); static public void RegisterMessageConverter(string messageType, Func converter) => messageConverters[messageType] = converter; static public Func 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); } } }