private async Task AcceptMessageEventAsync(MessageEventArgs msgEv, FlowBindings.FlowBindingElement binding) { try { Message rxMessage = SolaceNativeMsgAdapter.ConvertFromNativeMsg(msgEv.Message); bool continueDelivery = requestMgr.HandleIncoming(rxMessage); // If continueDelivery is false, the message was handled by the requestMgr so we drop it. if (continueDelivery && binding != null) { await binding.DispatchMessageAsync(rxMessage).ConfigureAwait(false); } else if (continueDelivery && binding == null) { // There is no callback on which to forward the message to, so dispatch // the message to the default session callback. await defaultAppMsgQueue.SendAsync(rxMessage).ConfigureAwait(false); } } finally { msgEv.Message.Dispose(); } }
private async Task <bool> SubscribeTopicAsyncInternal(Topic topic, BufferBlock <Message> messageQueue = null) { ITopic solTopic = ContextFactory.Instance.CreateTopic(topic.Name); FlowBindings.FlowBindingElement binding = null; if (messageQueue == null) { // Use default message block messageQueue = defaultAppMsgQueue; } bool newSubscription = flowBindings.AddBinding(topic, messageQueue, null, out binding); if (newSubscription && binding != null) { try { TaskCompletionSource <SessionEventArgs> tcs = new TaskCompletionSource <SessionEventArgs>(); IDispatchTarget dTarget = session.CreateDispatchTarget(solTopic, async(sender, msgEv) => await AcceptMessageEventAsync(msgEv, binding).ConfigureAwait(false)); binding.TopicDispatchTarget = dTarget; session.Subscribe(dTarget, SubscribeFlag.RequestConfirm, tcs); // Check subscription result var result = await tcs.Task.ConfigureAwait(false); if (result.Event == SessionEvent.SubscriptionOk) { return(true); } else { logger.LogError("Subscription error to topic: {0} responseCode {1} errorInfo: {2}", topic.Name, result.ResponseCode, result.Info); return(false); } } catch (Exception e) { binding.TopicDispatchTarget = null; flowBindings.RemoveBinding(topic, out binding); throw new MessagingException(e.Message, e); } } if (!newSubscription && binding != null) { // If existing subscription then ignore and return success return(true); } return(false); }
/// <summary> /// Unsubscribes from the destination asynchronously. For Queue destinations /// the flow is unbound and destroyed. Caller will also receive a flow state /// changed event if flow events were configured during subscribe. /// </summary> /// <param name="destination">The destination to unsubscribe.</param> /// <returns>True if the subscription was removed succussfully, false otherwise.</returns> public async Task <bool> UnsubscribeAsync(Destination destination) { FlowBindings.FlowBindingElement bind = null; var removed = flowBindings.RemoveBinding(destination, out bind); if (removed && bind != null) { try { // Unbind from queue if a flow is configured if (bind.Flow != null) { bind.Flow.Stop(); // 100 ms delay to avoid race-condition if still receiving msgs // and calling Flow.Ack which may cause deadlock and flow destroy will timeout. await Task.Delay(100); bind.Flow.Dispose(); bind.Flow = null; return(true); } // Unsubscribe from topic if topic dispatcher is configured if (bind.TopicDispatchTarget != null) { TaskCompletionSource <SessionEventArgs> tcs = new TaskCompletionSource <SessionEventArgs>(); session.Unsubscribe(bind.TopicDispatchTarget, SubscribeFlag.RequestConfirm, tcs); // Check unsubscribe result var result = await tcs.Task.ConfigureAwait(false); // Solace API use Subscription OK events for both subscribe and unsubscribe if (result.Event == SessionEvent.SubscriptionOk) { return(true); } else { logger.LogError("Unsubscribe error to topic: {0} responseCode {1} errorInfo: {2}", bind.Destination.Name, result.ResponseCode, result.Info); return(false); } } } catch (Exception e) { throw new MessagingException(e.Message, e); } } return(true); }
private async Task <bool> SubscribeQueueAsyncInternal(Queue queue, BufferBlock <Message> messageQueue = null, BufferBlock <FlowStateContext> flowEvtQueue = null, bool flowStartState = false) { FlowBindings.FlowBindingElement binding = null; if (messageQueue == null) { // Use default message block messageQueue = defaultAppMsgQueue; } bool newSubscription = flowBindings.AddBinding(queue, messageQueue, flowEvtQueue, out binding); if (newSubscription && binding != null) { try { // Configure flow properties var fp = new FlowProperties { AckMode = solaceOptions.ClientAck ? MessageAckMode.ClientAck : MessageAckMode.AutoAck, BindBlocking = false, // ensure we bind in non-blocking mode FlowStartState = flowStartState }; // Destination IEndpoint solQueue = null; if (queue.IsTemporary) { solQueue = session.CreateTemporaryQueue(queue.Name); } else { solQueue = ContextFactory.Instance.CreateQueue(queue.Name); } // Create the flow TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>(); IFlow flow = session.CreateFlow( fp, solQueue, null, async(sender, msgEv) => { await AcceptMessageEventAsync(msgEv, binding).ConfigureAwait(false); }, async(sender, flowEv) => { logger.LogDebug("FlowEvent: {0}, Info: {1}", flowEv.Event, flowEv.Info); var flowStateCtx = new FlowStateContext() { Info = flowEv.Info, ResponseCode = flowEv.ResponseCode }; switch (flowEv.Event) { case FlowEvent.UpNotice: flowStateCtx.State = FlowState.Up; tcs.TrySetResult(true); break; case FlowEvent.BindFailedError: flowStateCtx.State = FlowState.BindFailedError; logger.LogWarning(string.Format("Queue connection failure: {0}", flowEv.Event.ToString())); tcs.TrySetResult(false); break; case FlowEvent.DownError: flowStateCtx.State = FlowState.Down; break; case FlowEvent.FlowActive: flowStateCtx.State = FlowState.FlowActive; break; case FlowEvent.FlowInactive: flowStateCtx.State = FlowState.FlowInactive; break; default: break; } // Notify caller of the flow event await binding.DispatchFlowEventAsync(flowStateCtx).ConfigureAwait(false); }); binding.Flow = flow; return(await tcs.Task.ConfigureAwait(false)); } catch (Exception e) { binding.Flow = null; flowBindings.RemoveBinding(queue, out binding); throw new MessagingException(e.Message, e); } } if (!newSubscription && binding != null) { // If existing subscription then ignore and return success return(true); } return(false); }