public bool Notify(byte[] data, IRpcSerializer serializer) { Tuple <DataReceivedDelegate, bool>[] callbacks; lock (_callbacks) { callbacks = _callbacks.ToArray(); } var msg = serializer.DeserializeMessage <RpcMessage>(data); for (int i = 0; i < callbacks.Length; i++) { try { if (callbacks[i].Item1.Invoke(data, msg)) { if (callbacks[i].Item2) { lock (_callbacks) { _callbacks.Remove(callbacks[i]); } } return(true); } } catch (TargetInvocationException ex) { throw ex.InnerException ?? ex; } catch (Exception ex) { Console.WriteLine("Error in message notification: " + ex); throw; } } return(false); }
private async Task <TResult> WaitForMessageResultAsync <TResult>(TChannel channel, IRpcSerializer serializer, int callId, CancellationToken cancellationToken) where TResult : RpcMessage { var re = new AsyncManualResetEvent(false); using (cancellationToken.Register(() => { re.Set(); })) { TResult result = default; RegisterMessageCallback(channel, (data, bareMsg) => { if (bareMsg.CallId == callId) { if (bareMsg is TResult msg) { result = msg; } else { result = serializer.DeserializeMessage <TResult>(data); } re.Set(); return(true); } return(false); }, true); await re.WaitAsync(); return(result); } }
protected bool HandleRemoteMessage(TChannel channel, byte[] data, RpcMessage msg) { switch (msg.Type) { case RpcMessageType.CallMethod: { Exception resultException = null; RpcCallResultMessage resultMessage; IRpcServerContextObject remoteRpcServerContextObject = null; var m = msg as RpcMethodCallMessage ?? Serializer.DeserializeMessage <RpcMethodCallMessage>(data); try { LogTrace($"Received method call '{m.MethodName}' with instance id '{m.InstanceId}'"); var obj = LocalRepository.GetInstance(m.InstanceId); MethodInfo targetMethod; try { targetMethod = obj.GetType().GetMethod(m.MethodName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); } catch (AmbiguousMatchException) { targetMethod = obj.GetType() .GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) .SingleOrDefault(fm => fm.Name == m.MethodName && fm.GetParameters().Length == m.Arguments.Length); } if (targetMethod == null) { targetMethod = FindExplicitInterfaceImplementation(obj.GetType(), m.MethodName); } if (targetMethod == null) { throw new MissingMethodException(obj.GetType().FullName, m.MethodName); } LogTrace($"Resolved method '{targetMethod}' on object '{obj.GetType()}'"); var targetParameterTypes = targetMethod.GetParameters().Select(p => p.ParameterType).ToArray(); var args = new object[m.Arguments.Length]; var remoteRepository = GetRemoteRepository(channel); var rpcChannel = GetRpcChannelForClient(channel); for (int i = 0; i < m.Arguments.Length; i++) { args[i] = MessageFactory.DecodeRpcArgument(rpcChannel, LocalRepository, remoteRepository, Serializer, m.Arguments[i], targetParameterTypes[i]); } remoteRpcServerContextObject = obj as IRpcServerContextObject; if (remoteRpcServerContextObject != null) { LogTrace($"Object {m.InstanceId} implements IRpcServerContextObject, setting context"); remoteRpcServerContextObject.RpcChannel = channel; } var result = targetMethod.Invoke(obj, args); LogTrace("Method called without exception."); resultMessage = MessageFactory.CreateCallResultMessage(channel, LocalRepository, m, targetMethod, result); } catch (TargetInvocationException ex) { LogTrace($"Method call resulted in exception: {ex}"); resultException = ex.InnerException; resultMessage = MessageFactory.CreateExceptionResultMessage(m, ex.InnerException); } catch (Exception ex) { _logger?.LogError($"Failed to process message call: {ex}"); resultException = ex; resultMessage = MessageFactory.CreateExceptionResultMessage(m, ex); } finally { if (remoteRpcServerContextObject != null) { LogTrace($"Object {m.InstanceId} implements IRpcServerContextObject, removing context"); remoteRpcServerContextObject.RpcChannel = null; } } LogTrace("Serializing response."); byte[] response; try { response = Serializer.SerializeMessage(resultMessage); } catch (Exception ex) { if (resultMessage.Type == RpcMessageType.Exception) { _logger?.LogError(ex, $"Failed to serialize result exception of type '{resultException?.GetType()}'"); // if the exception is not serializable, do our best resultMessage = MessageFactory.CreateExceptionResultMessage(m, new Exception(resultException?.Message ?? "Internal Error")); response = Serializer.SerializeMessage(resultMessage); } else { throw; } } LogTrace("Sending response."); SendMessage(channel.GetStream(), response); LogTrace("Sent response"); return(true); } case RpcMessageType.RemoveInstance: { var m = Serializer.DeserializeMessage <RpcRemoveInstanceMessage>(data); LogTrace($"Removing instance '{m.InstanceId}'"); LocalRepository.RemoveInstance(m.InstanceId); var response = Serializer.SerializeMessage(new RpcMessage { CallId = m.CallId, Type = RpcMessageType.Ok }); SendMessage(channel.GetStream(), response); return(true); } } return(false); }