You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1085 lines
45 KiB
1085 lines
45 KiB
//------------------------------------------------------------------------------ |
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |
|
// CSDN博客:https://blog.csdn.net/qq_40374647 |
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567 |
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home |
|
// Github源代码仓库:https://github.com/RRQM |
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index |
|
// 交流QQ群:234762506 |
|
// 感谢您的下载和使用 |
|
//------------------------------------------------------------------------------ |
|
//------------------------------------------------------------------------------ |
|
using System; |
|
using System.Collections.Concurrent; |
|
using System.Collections.Generic; |
|
using System.Threading.Tasks; |
|
using TouchSocket.Core; |
|
using TouchSocket.Resources; |
|
using TouchSocket.Sockets; |
|
|
|
namespace TouchSocket.Rpc.TouchRpc |
|
{ |
|
public partial class RpcActor |
|
{ |
|
private readonly ConcurrentDictionary<long, TouchRpcCallContext> m_contextDic; |
|
|
|
/// <inheritdoc/> |
|
public object Caller { get; set; } |
|
|
|
/// <inheritdoc/> |
|
public RpcStore RpcStore { get; set; } |
|
|
|
/// <inheritdoc/> |
|
public SerializationSelector SerializationSelector { get; set; } |
|
|
|
#region Rpc |
|
|
|
/// <inheritdoc/> |
|
public T Invoke<T>(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) |
|
{ |
|
TouchRpcPackage rpcPackage = new TouchRpcPackage |
|
{ |
|
MethodName = invokeKey, |
|
SourceId = ID |
|
}; |
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(rpcPackage); |
|
ByteBlock byteBlock = new ByteBlock(); |
|
if (invokeOption == default) |
|
{ |
|
invokeOption = InvokeOption.WaitInvoke; |
|
} |
|
|
|
if (invokeOption.Token.CanBeCanceled) |
|
{ |
|
waitData.SetCancellationToken(invokeOption.Token); |
|
invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); |
|
} |
|
|
|
try |
|
{ |
|
rpcPackage.LoadInvokeOption(invokeOption); |
|
List<byte[]> datas = new List<byte[]>(); |
|
foreach (object parameter in parameters) |
|
{ |
|
datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); |
|
} |
|
rpcPackage.ParametersBytes = datas; |
|
rpcPackage.Package(byteBlock); |
|
|
|
switch (invokeOption.FeedbackType) |
|
{ |
|
case FeedbackType.OnlySend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
return default; |
|
} |
|
case FeedbackType.WaitSend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
break; |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return default; |
|
} |
|
case FeedbackType.WaitInvoke: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; |
|
resultContext.ThrowStatus(); |
|
if (resultContext.IsByRef) |
|
{ |
|
try |
|
{ |
|
for (int i = 0; i < parameters.Length; i++) |
|
{ |
|
parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); |
|
} |
|
} |
|
catch (System.Exception e) |
|
{ |
|
throw new Exception(e.Message); |
|
} |
|
} |
|
else |
|
{ |
|
parameters = null; |
|
} |
|
return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return default; |
|
} |
|
default: |
|
return default; |
|
} |
|
} |
|
finally |
|
{ |
|
WaitHandlePool.Destroy(waitData); |
|
byteBlock.Dispose(); |
|
} |
|
} |
|
|
|
/// <inheritdoc/> |
|
public void Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) |
|
{ |
|
TouchRpcPackage rpcPackage = new TouchRpcPackage |
|
{ |
|
MethodName = invokeKey, |
|
SourceId = ID |
|
}; |
|
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(rpcPackage); |
|
ByteBlock byteBlock = new ByteBlock(); |
|
if (invokeOption == default) |
|
{ |
|
invokeOption = InvokeOption.WaitInvoke; |
|
} |
|
|
|
if (invokeOption.Token.CanBeCanceled) |
|
{ |
|
waitData.SetCancellationToken(invokeOption.Token); |
|
invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); |
|
} |
|
|
|
try |
|
{ |
|
rpcPackage.LoadInvokeOption(invokeOption); |
|
List<byte[]> datas = new List<byte[]>(); |
|
foreach (object parameter in parameters) |
|
{ |
|
datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); |
|
} |
|
rpcPackage.ParametersBytes = datas; |
|
rpcPackage.Package(byteBlock); |
|
|
|
switch (invokeOption.FeedbackType) |
|
{ |
|
case FeedbackType.OnlySend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
} |
|
break; |
|
|
|
case FeedbackType.WaitSend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
break; |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
break; |
|
} |
|
case FeedbackType.WaitInvoke: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; |
|
resultContext.ThrowStatus(); |
|
if (resultContext.IsByRef) |
|
{ |
|
for (int i = 0; i < parameters.Length; i++) |
|
{ |
|
parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); |
|
} |
|
} |
|
else |
|
{ |
|
parameters = null; |
|
} |
|
break; |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
break; |
|
} |
|
default: |
|
break; |
|
} |
|
} |
|
finally |
|
{ |
|
WaitHandlePool.Destroy(waitData); |
|
byteBlock.Dispose(); |
|
} |
|
} |
|
|
|
/// <inheritdoc/> |
|
public void Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) |
|
{ |
|
TouchRpcPackage rpcPackage = new TouchRpcPackage |
|
{ |
|
MethodName = invokeKey, |
|
SourceId = ID |
|
}; |
|
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(rpcPackage); |
|
ByteBlock byteBlock = new ByteBlock(); |
|
if (invokeOption == default) |
|
{ |
|
invokeOption = InvokeOption.WaitInvoke; |
|
} |
|
|
|
if (invokeOption.Token.CanBeCanceled) |
|
{ |
|
waitData.SetCancellationToken(invokeOption.Token); |
|
invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); |
|
} |
|
|
|
try |
|
{ |
|
rpcPackage.LoadInvokeOption(invokeOption); |
|
if (parameters != null) |
|
{ |
|
List<byte[]> datas = new List<byte[]>(); |
|
foreach (object parameter in parameters) |
|
{ |
|
datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); |
|
} |
|
rpcPackage.ParametersBytes = datas; |
|
} |
|
|
|
rpcPackage.Package(byteBlock); |
|
|
|
switch (invokeOption.FeedbackType) |
|
{ |
|
case FeedbackType.OnlySend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
} |
|
break; |
|
|
|
case FeedbackType.WaitSend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
break; |
|
|
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
break; |
|
} |
|
case FeedbackType.WaitInvoke: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; |
|
resultContext.ThrowStatus(); |
|
break; |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
break; |
|
} |
|
default: |
|
break; |
|
} |
|
} |
|
finally |
|
{ |
|
WaitHandlePool.Destroy(waitData); |
|
byteBlock.Dispose(); |
|
} |
|
} |
|
|
|
/// <inheritdoc/> |
|
public T Invoke<T>(string invokeKey, IInvokeOption invokeOption, params object[] parameters) |
|
{ |
|
TouchRpcPackage rpcPackage = new TouchRpcPackage |
|
{ |
|
MethodName = invokeKey, |
|
SourceId = ID |
|
}; |
|
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(rpcPackage); |
|
ByteBlock byteBlock = new ByteBlock(); |
|
if (invokeOption == default) |
|
{ |
|
invokeOption = InvokeOption.WaitInvoke; |
|
} |
|
|
|
if (invokeOption.Token.CanBeCanceled) |
|
{ |
|
waitData.SetCancellationToken(invokeOption.Token); |
|
invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); |
|
} |
|
|
|
try |
|
{ |
|
rpcPackage.LoadInvokeOption(invokeOption); |
|
if (parameters != null) |
|
{ |
|
List<byte[]> datas = new List<byte[]>(); |
|
foreach (object parameter in parameters) |
|
{ |
|
datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); |
|
} |
|
rpcPackage.ParametersBytes = datas; |
|
} |
|
|
|
rpcPackage.Package(byteBlock); |
|
|
|
switch (invokeOption.FeedbackType) |
|
{ |
|
case FeedbackType.OnlySend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
return default; |
|
} |
|
case FeedbackType.WaitSend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return default; |
|
} |
|
case FeedbackType.WaitInvoke: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; |
|
resultContext.ThrowStatus(); |
|
return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return default; |
|
} |
|
|
|
default: |
|
return default; |
|
} |
|
} |
|
finally |
|
{ |
|
WaitHandlePool.Destroy(waitData); |
|
byteBlock.Dispose(); |
|
} |
|
} |
|
|
|
/// <inheritdoc/> |
|
public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) |
|
{ |
|
return EasyTask.Run(() => |
|
{ |
|
Invoke(invokeKey, invokeOption, parameters); |
|
}); |
|
} |
|
|
|
/// <inheritdoc/> |
|
public Task<T> InvokeAsync<T>(string invokeKey, IInvokeOption invokeOption, params object[] parameters) |
|
{ |
|
return EasyTask.Run(() => |
|
{ |
|
return Invoke<T>(invokeKey, invokeOption, parameters); |
|
}); |
|
} |
|
|
|
#endregion Rpc |
|
|
|
#region IdRpc |
|
|
|
/// <inheritdoc/> |
|
public void Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) |
|
{ |
|
if (string.IsNullOrEmpty(targetId)) |
|
{ |
|
throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); |
|
} |
|
|
|
if (string.IsNullOrEmpty(invokeKey)) |
|
{ |
|
throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); |
|
} |
|
|
|
if (IsService) |
|
{ |
|
if (this.TryFindRpcActor(targetId, out RpcActor actor)) |
|
{ |
|
actor.Invoke(invokeKey, invokeOption, parameters); |
|
return; |
|
} |
|
throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); |
|
} |
|
|
|
TouchRpcPackage rpcPackage = new TouchRpcPackage |
|
{ |
|
MethodName = invokeKey, |
|
Route = true, |
|
TargetId = targetId, |
|
SourceId = ID, |
|
}; |
|
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); |
|
ByteBlock byteBlock = new ByteBlock(); |
|
if (invokeOption == default) |
|
{ |
|
invokeOption = InvokeOption.WaitInvoke; |
|
} |
|
|
|
if (invokeOption.Token.CanBeCanceled) |
|
{ |
|
waitData.SetCancellationToken(invokeOption.Token); |
|
invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); |
|
} |
|
|
|
try |
|
{ |
|
rpcPackage.LoadInvokeOption(invokeOption); |
|
if (parameters != null) |
|
{ |
|
List<byte[]> datas = new List<byte[]>(); |
|
foreach (object parameter in parameters) |
|
{ |
|
datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); |
|
} |
|
rpcPackage.ParametersBytes = datas; |
|
} |
|
|
|
rpcPackage.Package(byteBlock); |
|
|
|
switch (invokeOption.FeedbackType) |
|
{ |
|
case FeedbackType.OnlySend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
} |
|
break; |
|
|
|
case FeedbackType.WaitSend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
break; |
|
|
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
break; |
|
} |
|
case FeedbackType.WaitInvoke: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; |
|
resultContext.ThrowStatus(); |
|
break; |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
break; |
|
} |
|
default: |
|
break; |
|
} |
|
} |
|
finally |
|
{ |
|
WaitHandlePool.Destroy(waitData); |
|
byteBlock.Dispose(); |
|
} |
|
} |
|
|
|
/// <inheritdoc/> |
|
public T Invoke<T>(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) |
|
{ |
|
if (string.IsNullOrEmpty(targetId)) |
|
{ |
|
throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); |
|
} |
|
|
|
if (string.IsNullOrEmpty(invokeKey)) |
|
{ |
|
throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); |
|
} |
|
|
|
if (IsService) |
|
{ |
|
if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) |
|
{ |
|
return rpcActor.Invoke<T>(invokeKey, invokeOption, parameters); |
|
} |
|
throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); |
|
} |
|
|
|
TouchRpcPackage rpcPackage = new TouchRpcPackage |
|
{ |
|
MethodName = invokeKey, |
|
TargetId = targetId, |
|
SourceId = ID, |
|
Route = true |
|
}; |
|
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); |
|
ByteBlock byteBlock = new ByteBlock(); |
|
if (invokeOption == default) |
|
{ |
|
invokeOption = InvokeOption.WaitInvoke; |
|
} |
|
|
|
if (invokeOption.Token.CanBeCanceled) |
|
{ |
|
waitData.SetCancellationToken(invokeOption.Token); |
|
invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); |
|
} |
|
|
|
try |
|
{ |
|
rpcPackage.LoadInvokeOption(invokeOption); |
|
if (parameters != null) |
|
{ |
|
List<byte[]> datas = new List<byte[]>(); |
|
foreach (object parameter in parameters) |
|
{ |
|
datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); |
|
} |
|
rpcPackage.ParametersBytes = datas; |
|
} |
|
|
|
rpcPackage.Package(byteBlock); |
|
|
|
switch (invokeOption.FeedbackType) |
|
{ |
|
case FeedbackType.OnlySend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
return default; |
|
} |
|
case FeedbackType.WaitSend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return default; |
|
} |
|
case FeedbackType.WaitInvoke: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; |
|
resultContext.ThrowStatus(); |
|
return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return default; |
|
} |
|
|
|
default: |
|
return default; |
|
} |
|
} |
|
finally |
|
{ |
|
WaitHandlePool.Destroy(waitData); |
|
byteBlock.Dispose(); |
|
} |
|
} |
|
|
|
/// <inheritdoc/> |
|
public void Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) |
|
{ |
|
if (string.IsNullOrEmpty(targetId)) |
|
{ |
|
throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); |
|
} |
|
|
|
if (string.IsNullOrEmpty(invokeKey)) |
|
{ |
|
throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); |
|
} |
|
|
|
if (IsService) |
|
{ |
|
if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) |
|
{ |
|
rpcActor.Invoke(invokeKey, invokeOption, ref parameters, types); |
|
return; |
|
} |
|
throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); |
|
} |
|
|
|
TouchRpcPackage rpcPackage = new TouchRpcPackage |
|
{ |
|
MethodName = invokeKey, |
|
TargetId = targetId, |
|
SourceId = ID, |
|
Route = true |
|
}; |
|
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); |
|
ByteBlock byteBlock = new ByteBlock(); |
|
if (invokeOption == default) |
|
{ |
|
invokeOption = InvokeOption.WaitInvoke; |
|
} |
|
|
|
if (invokeOption.Token.CanBeCanceled) |
|
{ |
|
waitData.SetCancellationToken(invokeOption.Token); |
|
invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); |
|
} |
|
|
|
try |
|
{ |
|
rpcPackage.LoadInvokeOption(invokeOption); |
|
List<byte[]> datas = new List<byte[]>(); |
|
foreach (object parameter in parameters) |
|
{ |
|
datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); |
|
} |
|
rpcPackage.ParametersBytes = datas; |
|
rpcPackage.Package(byteBlock); |
|
|
|
switch (invokeOption.FeedbackType) |
|
{ |
|
case FeedbackType.OnlySend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
return; |
|
} |
|
case FeedbackType.WaitSend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return; |
|
} |
|
case FeedbackType.WaitInvoke: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; |
|
resultContext.ThrowStatus(); |
|
if (resultContext.IsByRef) |
|
{ |
|
for (int i = 0; i < parameters.Length; i++) |
|
{ |
|
parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); |
|
} |
|
} |
|
else |
|
{ |
|
parameters = null; |
|
} |
|
break; |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return; |
|
} |
|
|
|
default: |
|
return; |
|
} |
|
} |
|
finally |
|
{ |
|
WaitHandlePool.Destroy(waitData); |
|
byteBlock.Dispose(); |
|
} |
|
} |
|
|
|
/// <inheritdoc/> |
|
public T Invoke<T>(string targetId, string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) |
|
{ |
|
if (string.IsNullOrEmpty(targetId)) |
|
{ |
|
throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); |
|
} |
|
|
|
if (string.IsNullOrEmpty(invokeKey)) |
|
{ |
|
throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); |
|
} |
|
|
|
if (IsService) |
|
{ |
|
if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) |
|
{ |
|
return rpcActor.Invoke<T>(invokeKey, invokeOption, ref parameters, types); |
|
} |
|
throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); |
|
} |
|
|
|
TouchRpcPackage rpcPackage = new TouchRpcPackage |
|
{ |
|
MethodName = invokeKey, |
|
TargetId = targetId, |
|
SourceId = ID, |
|
Route = true |
|
}; |
|
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); |
|
ByteBlock byteBlock = new ByteBlock(); |
|
if (invokeOption == default) |
|
{ |
|
invokeOption = InvokeOption.WaitInvoke; |
|
} |
|
|
|
if (invokeOption.Token.CanBeCanceled) |
|
{ |
|
waitData.SetCancellationToken(invokeOption.Token); |
|
invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); |
|
} |
|
|
|
try |
|
{ |
|
rpcPackage.LoadInvokeOption(invokeOption); |
|
List<byte[]> datas = new List<byte[]>(); |
|
foreach (object parameter in parameters) |
|
{ |
|
datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); |
|
} |
|
rpcPackage.ParametersBytes = datas; |
|
rpcPackage.Package(byteBlock); |
|
|
|
switch (invokeOption.FeedbackType) |
|
{ |
|
case FeedbackType.OnlySend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
return default; |
|
} |
|
case FeedbackType.WaitSend: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return default; |
|
} |
|
case FeedbackType.WaitInvoke: |
|
{ |
|
Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); |
|
switch (waitData.Wait(invokeOption.Timeout)) |
|
{ |
|
case WaitDataStatus.SetRunning: |
|
{ |
|
TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; |
|
resultContext.ThrowStatus(); |
|
if (resultContext.IsByRef) |
|
{ |
|
for (int i = 0; i < parameters.Length; i++) |
|
{ |
|
parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); |
|
} |
|
} |
|
else |
|
{ |
|
parameters = null; |
|
} |
|
return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); |
|
} |
|
case WaitDataStatus.Overtime: |
|
{ |
|
throw new TimeoutException("等待结果超时"); |
|
} |
|
} |
|
return default; |
|
} |
|
|
|
default: |
|
return default; |
|
} |
|
} |
|
finally |
|
{ |
|
WaitHandlePool.Destroy(waitData); |
|
byteBlock.Dispose(); |
|
} |
|
} |
|
|
|
/// <inheritdoc/> |
|
public Task InvokeAsync(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) |
|
{ |
|
return EasyTask.Run(() => |
|
{ |
|
Invoke(targetId, invokeKey, invokeOption, parameters); |
|
}); |
|
} |
|
|
|
/// <inheritdoc/> |
|
public Task<T> InvokeAsync<T>(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) |
|
{ |
|
return EasyTask.Run(() => |
|
{ |
|
return Invoke<T>(targetId, invokeKey, invokeOption, parameters); |
|
}); |
|
} |
|
|
|
#endregion IdRpc |
|
|
|
private void CanceledInvoke(object obj) |
|
{ |
|
if (obj is CanceledPackage canceled) |
|
{ |
|
using (ByteBlock byteBlock = new ByteBlock()) |
|
{ |
|
canceled.Package(byteBlock); |
|
Send(TouchRpcUtility.P_204_CancelInvoke, byteBlock); |
|
} |
|
} |
|
} |
|
|
|
private void InvokeThis(object o) |
|
{ |
|
try |
|
{ |
|
TouchRpcPackage rpcPackage = (TouchRpcPackage)o; |
|
|
|
List<byte[]> psData = rpcPackage.ParametersBytes; |
|
if (rpcPackage.Feedback == FeedbackType.WaitSend) |
|
{ |
|
using (ByteBlock returnByteBlock = new ByteBlock()) |
|
{ |
|
var methodName = rpcPackage.MethodName; |
|
var parametersBytes = rpcPackage.ParametersBytes; |
|
|
|
rpcPackage.SwitchId(); |
|
rpcPackage.MethodName = default; |
|
rpcPackage.ParametersBytes = default; |
|
rpcPackage.Status = TouchSocketStatus.Success.ToValue(); |
|
rpcPackage.Package(returnByteBlock); |
|
Send(TouchRpcUtility.P_1200_Invoke_Response, returnByteBlock); |
|
|
|
rpcPackage.SwitchId(); |
|
rpcPackage.MethodName= methodName; |
|
rpcPackage.ParametersBytes = parametersBytes; |
|
} |
|
} |
|
|
|
InvokeResult invokeResult = new InvokeResult(); |
|
object[] ps = null; |
|
MethodInstance methodInstance = GetInvokeMethod?.Invoke(rpcPackage.MethodName); |
|
TouchRpcCallContext callContext = null; |
|
if (methodInstance != null) |
|
{ |
|
try |
|
{ |
|
if (methodInstance.IsEnable) |
|
{ |
|
callContext = new TouchRpcCallContext() |
|
{ |
|
Caller = Caller, |
|
MethodInstance = methodInstance, |
|
TouchRpcPackage = rpcPackage |
|
}; |
|
|
|
m_contextDic.TryAdd(rpcPackage.Sign, callContext); |
|
|
|
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) |
|
{ |
|
ps = new object[methodInstance.ParameterTypes.Length]; |
|
ps[0] = callContext; |
|
for (int i = 0; i < psData.Count; i++) |
|
{ |
|
ps[i + 1] = SerializationSelector.DeserializeParameter(rpcPackage.SerializationType, psData[i], methodInstance.ParameterTypes[i + 1]); |
|
} |
|
} |
|
else |
|
{ |
|
ps = new object[methodInstance.ParameterTypes.Length]; |
|
for (int i = 0; i < methodInstance.ParameterTypes.Length; i++) |
|
{ |
|
ps[i] = SerializationSelector.DeserializeParameter(rpcPackage.SerializationType, psData[i], methodInstance.ParameterTypes[i]); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
invokeResult.Status = InvokeStatus.UnEnable; |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
invokeResult.Status = InvokeStatus.Exception; |
|
invokeResult.Message = ex.Message; |
|
} |
|
} |
|
else |
|
{ |
|
invokeResult.Status = InvokeStatus.UnFound; |
|
} |
|
|
|
if (invokeResult.Status == InvokeStatus.Ready) |
|
{ |
|
IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); |
|
if (rpcServer is ITransientRpcServer transientRpcServer) |
|
{ |
|
transientRpcServer.CallContext = callContext; |
|
} |
|
invokeResult = RpcStore.Execute(rpcServer, ps, callContext); |
|
} |
|
|
|
if (rpcPackage.Feedback == FeedbackType.OnlySend) |
|
{ |
|
return; |
|
} |
|
|
|
switch (invokeResult.Status) |
|
{ |
|
case InvokeStatus.UnFound: |
|
{ |
|
rpcPackage.Status = TouchSocketStatus.RpcMethodNotFind.ToValue(); |
|
break; |
|
} |
|
case InvokeStatus.Success: |
|
{ |
|
if (methodInstance.HasReturn) |
|
{ |
|
rpcPackage.ReturnParameterBytes = SerializationSelector.SerializeParameter(rpcPackage.SerializationType, invokeResult.Result); |
|
} |
|
else |
|
{ |
|
rpcPackage.ReturnParameterBytes = null; |
|
} |
|
|
|
if (methodInstance.IsByRef) |
|
{ |
|
rpcPackage.IsByRef = true; |
|
rpcPackage.ParametersBytes = new List<byte[]>(); |
|
|
|
int i = 0; |
|
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) |
|
{ |
|
i = 1; |
|
} |
|
for (; i < ps.Length; i++) |
|
{ |
|
rpcPackage.ParametersBytes.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, ps[i])); |
|
} |
|
} |
|
else |
|
{ |
|
rpcPackage.ParametersBytes = null; |
|
} |
|
|
|
rpcPackage.Status = TouchSocketStatus.Success.ToValue(); |
|
break; |
|
} |
|
case InvokeStatus.UnEnable: |
|
{ |
|
rpcPackage.Status = TouchSocketStatus.RpcMethodDisable.ToValue(); |
|
break; |
|
} |
|
case InvokeStatus.InvocationException: |
|
{ |
|
rpcPackage.Status = TouchSocketStatus.RpcInvokeException.ToValue(); |
|
rpcPackage.Message = invokeResult.Message; |
|
break; |
|
} |
|
case InvokeStatus.Exception: |
|
{ |
|
rpcPackage.Status = TouchSocketStatus.Exception.ToValue(); |
|
rpcPackage.Message = invokeResult.Message; |
|
break; |
|
} |
|
default: |
|
return; |
|
} |
|
|
|
m_contextDic.TryRemove(rpcPackage.Sign, out _); |
|
|
|
using (ByteBlock byteBlock = new ByteBlock()) |
|
{ |
|
rpcPackage.MethodName = default; |
|
rpcPackage.SwitchId(); |
|
rpcPackage.Package(byteBlock); |
|
Send(TouchRpcUtility.P_1200_Invoke_Response, byteBlock); |
|
} |
|
} |
|
catch |
|
{ |
|
} |
|
} |
|
} |
|
} |