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); } }); }