void HandleInternal(IMessage message, IMessagingSource sender)
        {
            IChannelHandlerContext context = this.capturedContext;

            try
            {
                Contract.Assert(message != null);

                PerformanceCounters.MessagesReceivedPerSecond.Increment();
                this.PublishToClientAsync(context, message, sender).OnFault(ShutdownOnPublishFaultAction, context);
                message = null;
            }
            catch (MessagingException ex)
            {
                this.ShutdownOnReceiveError(ex);
            }
            catch (Exception ex)
            {
                ShutdownOnError(context, ReceiveProcessingScope, ex);
            }
            finally
            {
                message?.Payload.SafeRelease();
            }
        }
Example #2
0
 public AckPendingMessageState(IMessage message, IMessagingSource callback, PublishPacket packet)
 {
     this.SequenceNumber   = message.SequenceNumber;
     this.PacketId         = packet.PacketId;
     this.QualityOfService = packet.QualityOfService;
     this.FeedbackChannel  = new MessageFeedbackChannel(message.Id, callback);
     this.StartTimestamp   = PreciseTimeSpan.FromStart;
 }
 public void RegisterSource(IMessagingSource source)
 {
     {
         this.sources.Add(source);
         if (this.messagingChannel != null)
         {
             source.BindMessagingChannel(this.messagingChannel);
         }
     }
 }
 void IMessagingChannel.Handle(IMessage message, IMessagingSource callback)
 {
     if (this.capturedContext.Executor.InEventLoop)
     {
         this.HandleInternal(message, callback);
     }
     else
     {
         this.capturedContext.Executor.Execute((s, m) => this.HandleInternal((IMessage)m, (IMessagingSource)s), callback, message);
     }
 }
        async Task PublishToClientQos2Async(IChannelHandlerContext context, IMessage message, IMessagingSource callback, PublishPacket packet)
        {
            await Qos2Semaphore.WaitAsync(this.lifetimeCancellation.Token); // this ensures proper ordering of messages

            Task deliveryTask;

            try
            {
                int packetId = packet.PacketId;
                IQos2MessageDeliveryState messageInfo = await this.qos2StateProvider.GetMessageAsync(this.identity, packetId);

                if (messageInfo != null && message.SequenceNumber != messageInfo.SequenceNumber)
                {
                    await this.qos2StateProvider.DeleteMessageAsync(this.identity, packetId, messageInfo);

                    messageInfo = null;
                }

                if (messageInfo == null)
                {
                    deliveryTask = this.publishPubRecProcessor.SendRequestAsync(context, packet,
                                                                                new AckPendingMessageState(message, callback, packet));
                }
                else
                {
                    deliveryTask = this.PublishReleaseToClientAsync(context, packetId, new MessageFeedbackChannel(message.Id, callback), messageInfo, PreciseTimeSpan.FromStart);
                }
            }
            finally
            {
                try
                {
                    this.Qos2Semaphore.Release();
                }
                catch (ObjectDisposedException)
                { }
            }

            await deliveryTask;
        }
 Task PublishToClientQos1Async(IChannelHandlerContext context, IMessage message, IMessagingSource callback, PublishPacket packet)
 {
     return(this.publishPubAckProcessor.SendRequestAsync(context, packet,
                                                         new AckPendingMessageState(message, callback, packet)));
 }
 Task PublishToClientQos0Async(IChannelHandlerContext context, IMessage message, IMessagingSource callback, PublishPacket packet)
 {
     if (message.DeliveryCount == 0)
     {
         return(Task.WhenAll(
                    callback.CompleteAsync(message.Id),
                    Util.WriteMessageAsync(context, packet)));
     }
     else
     {
         return(callback.CompleteAsync(message.Id));
     }
 }
        static async Task RejectMessageAsync(string messageId, IMessagingSource callback)
        {
            await callback.RejectAsync(messageId); // awaiting guarantees that we won't complete consecutive message before this is completed.

            PerformanceCounters.MessagesRejectedPerSecond.Increment();
        }
        async Task PublishToClientAsync(IChannelHandlerContext context, IMessage message, IMessagingSource callback)
        {
            PublishPacket packet = null;

            try
            {
                using (message)
                {
                    message.Properties[TemplateParameters.DeviceIdTemplateParam] = this.DeviceId;

                    QualityOfService qos;
                    QualityOfService maxRequestedQos;
                    if (this.TryMatchSubscription(message.Address, message.CreatedTimeUtc, out maxRequestedQos))
                    {
                        qos = Util.DeriveQos(message, this.settings, this.ChannelId, this.Id);
                        if (maxRequestedQos < qos)
                        {
                            qos = maxRequestedQos;
                        }
                    }
                    else
                    {
                        // no matching subscription found - complete the message without publishing
                        await RejectMessageAsync(message.Id, callback);

                        return;
                    }

                    packet = Util.ComposePublishPacket(context, message, qos, context.Channel.Allocator);
                    switch (qos)
                    {
                    case QualityOfService.AtMostOnce:
                        await this.PublishToClientQos0Async(context, message, callback, packet);

                        break;

                    case QualityOfService.AtLeastOnce:
                        await this.PublishToClientQos1Async(context, message, callback, packet);

                        break;

                    case QualityOfService.ExactlyOnce:
                        if (this.maxSupportedQosToClient >= QualityOfService.ExactlyOnce)
                        {
                            await this.PublishToClientQos2Async(context, message, callback, packet);
                        }
                        else
                        {
                            throw new ProtocolGatewayException(ErrorCode.QoSLevelNotSupported, "Requested QoS level is not supported.");
                        }
                        break;

                    default:
                        throw new ProtocolGatewayException(ErrorCode.QoSLevelNotSupported, "Requested QoS level is not supported.");
                    }
                }
                this.lastClientActivityTime = DateTime.UtcNow; // note last client activity - used in handling disconnects on keep-alive timeout
            }
            catch (Exception ex)
            {
                ReferenceCountUtil.SafeRelease(packet);
                ShutdownOnError(context, "<- PUBLISH", ex);
            }
        }
 public MessageFeedbackChannel(string messageId, IMessagingSource callback)
 {
     this.messageId = messageId;
     this.callback  = callback;
 }