/* Tesses.RPC A simple RPC library for .NET Copyright (C) 2023 Mike Nolan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; namespace Tesses.RPC { public abstract class MessageHandler { public abstract void SendMessage(string msg); public void OnMessageReceived(string msg) { MessageRecv?.Invoke(msg); } internal event Action MessageRecv; } public sealed class MessageReceived { Action reply; internal MessageReceived(T data,bool needReply,long id,Action reply) { Data = data; NeedReply = needReply; this.reply=reply; Id = id; } public long Id {get;private set;} public T Data {get;private set;} public bool NeedReply {get;private set;} public void Reply(TType msg) { reply?.Invoke(msg); } } public sealed class JsonMessager where TEnum : Enum { Dictionary> resp)> items=new Dictionary> resp)>(); MessageHandler handler; public JsonMessager(MessageHandler handler) { this.handler = handler; this.handler.MessageRecv += message_recv; } private void message_recv(string msg) { var res= JsonConvert.DeserializeObject>(msg); if(res != null && items.ContainsKey(res.Type)) { items[res.Type].resp?.Invoke(res); } } private event Action> recv_res; public void Register(TEnum val) where T : TType { Register(val,(ctx)=>{}); } public void Register(TEnum val,Action> recv) where T : TType { if(!items.ContainsKey(val)) { Action> msger= (msg)=>{ if(recv!=null && msg.MessageState != MessageState.ResponseNoForget) { MessageReceived msg0=new MessageReceived(msg.Value.ToObject(),msg.MessageState != MessageState.Forget ,msg.Id,(reply)=>{ SendMessageResponse(reply,msg.Id); }); recv?.Invoke(msg0); }else if(msg.MessageState == MessageState.ResponseNoForget){ recv_res?.Invoke(msg); } }; items.Add(val,(typeof(T),msger)); } } private void SendMessageResponse(TType msg,long msgId) { foreach(var item in items) { if(item.Value.type == msg.GetType()) { JsonMessage jsonMessage = new JsonMessage(); jsonMessage.Type=item.Key; jsonMessage.Value=JToken.FromObject(msg); jsonMessage.Id = msgId; jsonMessage.MessageState = MessageState.ResponseNoForget; string text=JsonConvert.SerializeObject(jsonMessage); handler.SendMessage(text); return; } } } public void SendMessage(TType msg) { foreach(var item in items) { if(item.Value.type == msg.GetType()) { JsonMessage jsonMessage = new JsonMessage(); jsonMessage.Type=item.Key; jsonMessage.Value=JToken.FromObject(msg); jsonMessage.Id = JsonMessage.GetNewId(); jsonMessage.MessageState = MessageState.Forget; string text=JsonConvert.SerializeObject(jsonMessage); handler.SendMessage(text); return; } } } public void SendMessage(TType msg,Action resp) where TResponse : TType { foreach(var item in items) { if(item.Value.type == msg.GetType()) { JsonMessage jsonMessage = new JsonMessage(); jsonMessage.Type=item.Key; jsonMessage.Value=JToken.FromObject(msg); jsonMessage.Id = JsonMessage.GetNewId(); jsonMessage.MessageState = MessageState.RequestNoForget; string text=JsonConvert.SerializeObject(jsonMessage); recv_res += (e)=>{ if(e.Id == jsonMessage.Id && e.MessageState == MessageState.ResponseNoForget) { if(items.ContainsKey(e.Type) && items[e.Type].type == typeof(TResponse)) { resp?.Invoke(e.Value.ToObject()); } } }; handler.SendMessage(text); return; } } } internal enum MessageState { Forget=0, RequestNoForget=1, ResponseNoForget=2 } private class JsonMessage where TEnum2 : Enum { private static long _curId=0; internal static long GetNewId() { return _curId++; } [JsonConverter(typeof(StringEnumConverter))] public TEnum2 Type {get;set;} public JToken Value {get;set;} public long Id {get;set;} public MessageState MessageState {get;set;} } } }