191 lines
6.8 KiB
C#
191 lines
6.8 KiB
C#
/*
|
|
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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
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<string> MessageRecv;
|
|
}
|
|
public sealed class MessageReceived<T,TType>
|
|
{
|
|
Action<TType> reply;
|
|
internal MessageReceived(T data,bool needReply,Action<TType> reply)
|
|
{
|
|
Data = data;
|
|
NeedReply = needReply;
|
|
this.reply=reply;
|
|
}
|
|
public T Data {get;private set;}
|
|
public bool NeedReply {get;private set;}
|
|
public void Reply(TType msg)
|
|
{
|
|
reply?.Invoke(msg);
|
|
}
|
|
}
|
|
public sealed class JsonMessager<TEnum,TType> where TEnum : Enum
|
|
{
|
|
Dictionary<TEnum,(Type type,Action<JsonMessage<TEnum>> resp)> items=new Dictionary<TEnum, (Type type,Action<JsonMessage<TEnum>> 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<JsonMessage<TEnum>>(msg);
|
|
if(res != null && items.ContainsKey(res.Type))
|
|
{
|
|
|
|
|
|
items[res.Type].resp?.Invoke(res);
|
|
}
|
|
}
|
|
private event Action<JsonMessage<TEnum>> recv_res;
|
|
public void Register<T>(TEnum val) where T : TType
|
|
{
|
|
Register<T>(val,(ctx)=>{});
|
|
}
|
|
public void Register<T>(TEnum val,Action<MessageReceived<T,TType>> recv) where T : TType
|
|
{
|
|
|
|
if(!items.ContainsKey(val))
|
|
{
|
|
Action<JsonMessage<TEnum>> msger= (msg)=>{
|
|
if(recv!=null && msg.MessageState != MessageState.ResponseNoForget)
|
|
{
|
|
|
|
MessageReceived<T,TType> msg0=new MessageReceived<T,TType>(msg.Value.ToObject<T>(),msg.MessageState != MessageState.Forget ,(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<TEnum> jsonMessage = new JsonMessage<TEnum>();
|
|
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<TEnum> jsonMessage = new JsonMessage<TEnum>();
|
|
jsonMessage.Type=item.Key;
|
|
jsonMessage.Value=JToken.FromObject(msg);
|
|
jsonMessage.Id = JsonMessage<TEnum>.GetNewId();
|
|
jsonMessage.MessageState = MessageState.Forget;
|
|
|
|
string text=JsonConvert.SerializeObject(jsonMessage);
|
|
handler.SendMessage(text);
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
public void SendMessage<TResponse>(TType msg,Action<TResponse> resp) where TResponse : TType
|
|
{
|
|
foreach(var item in items)
|
|
{
|
|
if(item.Value.type == msg.GetType())
|
|
{
|
|
JsonMessage<TEnum> jsonMessage = new JsonMessage<TEnum>();
|
|
jsonMessage.Type=item.Key;
|
|
jsonMessage.Value=JToken.FromObject(msg);
|
|
jsonMessage.Id = JsonMessage<TEnum>.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<TResponse>());
|
|
}
|
|
}
|
|
};
|
|
handler.SendMessage(text);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal enum MessageState
|
|
{
|
|
Forget=0,
|
|
RequestNoForget=1,
|
|
ResponseNoForget=2
|
|
}
|
|
|
|
private class JsonMessage<TEnum2> 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;}
|
|
}
|
|
}
|
|
}
|