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