Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
            }
        }
Esempio n. 3
0
        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);
        }