Example #1
0
 private bool TriggerWaitHandle(string datasocketID, TMessage msg)
 {
     if (PendingResponseWaitHandles.ContainsKey(datasocketID))
     {
         ResponseWaitHandle hndl = PendingResponseWaitHandles[datasocketID];
         PendingResponseWaitHandles.Remove(datasocketID);
         hndl.Response = msg;
         hndl.Set();
         return(true);
     }
     return(false);
 }
        /// <summary>
        /// Processes the incoming return value message from the recipient connection.
        /// </summary>
        /// <param name="actionId">byte associated with the RpcCallMessageAction enum.</param>
        /// <param name="message">Message containing the frames for the return value.</param>
        private void ProcessRpcReturnAction(byte actionId, MqMessage message)
        {
            // Execute the processing on the worker thread.
            Task.Run(() =>
            {
                // Read the return Id.
                var returnId = message[0].ReadUInt16(0);


                ResponseWaitHandle callWaitHandle = ProxyWaitOperations.Remove(returnId);
                // Try to get the outstanding wait from the return id.  If it does not exist, the has already completed.
                if (callWaitHandle != null)
                {
                    callWaitHandle.Message = message;

                    callWaitHandle.MessageActionId = actionId;

                    // Release the wait event.
                    callWaitHandle.ReturnResetEvent.Set();
                }
            });
        }
        /// <summary>
        /// Processes the incoming Rpc call from the recipient connection.
        /// </summary>
        /// <param name="actionId">byte associated with the RpcCallMessageAction enum.</param>
        /// <param name="message">Message containing the Rpc call.</param>
        private void ProcessRpcCallAction(byte actionId, MqMessage message)
        {
            // Execute the processing on the worker thread.
            Task.Run(() =>
            {
                var messageType = (RpcCallMessageAction)actionId;

                // Retrieve a serialization cache to work with.
                var serialization         = Session.SerializationCache.Get(message);
                ushort recMessageReturnId = 0;

                try
                {
                    // Determine if this call has a return value.
                    if (messageType == RpcCallMessageAction.MethodCall)
                    {
                        recMessageReturnId = serialization.MessageReader.ReadUInt16();
                    }

                    // Read the string service name, method and number of arguments.
                    var recServiceName   = serialization.MessageReader.ReadString();
                    var recMethodName    = serialization.MessageReader.ReadString();
                    var recArgumentCount = serialization.MessageReader.ReadByte();

                    // Verify that the requested service exists.
                    if (Services.ContainsKey(recServiceName) == false)
                    {
                        throw new Exception($"Service '{recServiceName}' does not exist.");
                    }

                    // Get the service from the instance list.
                    var service = Services[recServiceName];

                    // Get the actual method.  TODO: Might want to cache this for performance purposes.
                    var methodInfo       = service.GetType().GetMethod(recMethodName);
                    var methodParameters = methodInfo.GetParameters();

                    // Determine if the last parameter is a cancellation token.
                    var lastParam = methodInfo.GetParameters().LastOrDefault();

                    ResponseWaitHandle cancellationWait = null;

                    // If the past parameter is a cancellation token, setup a return wait for this call to allow for remote cancellation.
                    if (recMessageReturnId != 0 && lastParam?.ParameterType == typeof(CancellationToken))
                    {
                        cancellationWait = _remoteWaitOperations.CreateWaitHandle(recMessageReturnId);

                        cancellationWait.TokenSource = new CancellationTokenSource();
                        cancellationWait.Token       = cancellationWait.TokenSource.Token;
                    }

                    // Setup the parameters to pass to the invoked method.
                    object[] parameters = new object[recArgumentCount + (cancellationWait == null ? 0 : 1)];

                    // Determine if we have any parameters to pass to the invoked method.
                    if (recArgumentCount > 0)
                    {
                        serialization.PrepareDeserializeReader();


                        // Parse each parameter to the parameter list.
                        for (int i = 0; i < recArgumentCount; i++)
                        {
                            parameters[i] = serialization.DeserializeFromReader(methodParameters[i].ParameterType, i);
                        }
                    }

                    // Add the cancellation token to the parameters.
                    if (cancellationWait != null)
                    {
                        parameters[parameters.Length - 1] = cancellationWait.Token;
                    }


                    object returnValue;
                    try
                    {
                        // Invoke the requested method.
                        returnValue = methodInfo.Invoke(service, parameters);
                    }
                    catch (Exception ex)
                    {
                        // Determine if this method was waited on.  If it was and an exception was thrown,
                        // Let the recipient session know an exception was thrown.
                        if (recMessageReturnId != 0 &&
                            ex.InnerException?.GetType() != typeof(OperationCanceledException))
                        {
                            SendRpcException(serialization, ex, recMessageReturnId);
                        }
                        return;
                    }
                    finally
                    {
                        _remoteWaitOperations.Remove(recMessageReturnId);
                    }


                    // Determine what to do with the return value.
                    if (messageType == RpcCallMessageAction.MethodCall)
                    {
                        // Reset the stream.
                        serialization.Stream.SetLength(0);
                        serialization.MessageWriter.Clear();

                        // Write the return id.
                        serialization.MessageWriter.Write(recMessageReturnId);

                        // Serialize the return value and add it to the stream.

                        serialization.SerializeToWriter(returnValue, 0);

                        // Send the return value message to the recipient.


                        SendHandlerMessage((byte)RpcCallMessageAction.MethodReturn,
                                           serialization.MessageWriter.ToMessage(true));
                    }
                }
                catch (Exception ex)
                {
                    // If an exception occurred, notify the recipient connection.
                    SendRpcException(serialization, ex, recMessageReturnId);
                }
                finally
                {
                    // Return the serialization to the cache to be reused.
                    Session.SerializationCache.Put(serialization);
                }
            });
        }