/*
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;}
}
}
}