IEnumerable <TestScenarioStep> GetPart2SpecificSteps(Func <object> currentMessageFunc) { yield return(TestScenarioStep.ReadMore()); var packets = new Packet[2]; for (int i = packets.Length - 1; i >= 0; i--) { packets[i] = Assert.IsAssignableFrom <Packet>(currentMessageFunc()); if (i > 0) { yield return(TestScenarioStep.ReadMore()); } } PublishPacket qos1Packet = Assert.Single(packets.OfType <PublishPacket>()); Assert.Equal(QualityOfService.AtLeastOnce, qos1Packet.QualityOfService); this.AssertPacketCoreValue(qos1Packet, Encoding.ASCII.GetString(qos1Packet.Payload.ToArray())); PubRelPacket pubRelQos2Packet = Assert.Single(packets.OfType <PubRelPacket>()); yield return(TestScenarioStep.Write( false, PubAckPacket.InResponseTo(qos1Packet), PubCompPacket.InResponseTo(pubRelQos2Packet), DisconnectPacket.Instance)); }
public void OnPublish(IChannelHandlerContext context, PublishPacket packet) { switch (packet.QualityOfService) { case QualityOfService.AtMostOnce: publishCallback(packet); break; case QualityOfService.AtLeastOnce: publishCallback(packet); if (packet.PacketId != -1) { context.WriteAndFlushAsync(PubAckPacket.InResponseTo(packet)); } break; case QualityOfService.ExactlyOnce: if (packet.PacketId != -1) { var pubRecPacket = PubRecPacket.InResponseTo(packet); PendingQoS2Publish pendingQoS2Publish = new PendingQoS2Publish(packet, pubRecPacket); pendingIncomingQoS2Publishes.TryAdd(pubRecPacket.PacketId, pendingQoS2Publish); packet.Retain(); pendingQoS2Publish.Retransmit(eventLoopGroup.GetNext(), sendAndFlushAsync); context.WriteAndFlushAsync(pubRecPacket); } break; } }
async Task PublishToServerAsync(IChannelHandlerContext context, IMessagingServiceClient sendingClient, PublishPacket packet, string messageType) { if (!this.ConnectedToService) { packet.Release(); return; } PreciseTimeSpan startedTimestamp = PreciseTimeSpan.FromStart; this.ResumeReadingIfNecessary(context); IMessage message = null; try { message = sendingClient.CreateMessage(packet.TopicName, packet.Payload); Util.CompleteMessageFromPacket(message, packet, this.settings); if (messageType != null) { message.Properties[this.settings.ServicePropertyPrefix + MessagePropertyNames.MessageType] = messageType; } await sendingClient.SendAsync(message); PerformanceCounters.MessagesSentPerSecond.Increment(); if (!this.IsInState(StateFlags.Closed)) { switch (packet.QualityOfService) { case QualityOfService.AtMostOnce: // no response necessary PerformanceCounters.InboundMessageProcessingTime.Register(startedTimestamp); break; case QualityOfService.AtLeastOnce: Util.WriteMessageAsync(context, PubAckPacket.InResponseTo(packet)) .OnFault(ShutdownOnWriteFaultAction, context); PerformanceCounters.InboundMessageProcessingTime.Register(startedTimestamp); // todo: assumes PUBACK is written out sync break; case QualityOfService.ExactlyOnce: ShutdownOnError(context, InboundPublishProcessingScope, new ProtocolGatewayException(ErrorCode.ExactlyOnceQosNotSupported, "QoS 2 is not supported.")); break; default: throw new ProtocolGatewayException(ErrorCode.UnknownQosType, "Unexpected QoS level: " + packet.QualityOfService.ToString()); } } message = null; } finally { message?.Dispose(); } }
async Task GetPart1SpecificSteps(IChannel channel, ReadListeningHandler readHandler) { int publishQoS1PacketId = GetRandomPacketId(); await channel.WriteAndFlushManyAsync( new PublishPacket(QualityOfService.AtMostOnce, false, false) { //TopicName = string.Format("devices/{0}/messages/log/verbose/", clientId), TopicName = $"devices/{this.clientId}/messages/events", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry-QoS0\"}")) }, new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = publishQoS1PacketId, TopicName = $"devices/{this.clientId}/messages/events", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry\"}")) }); var packets = new Packet[5]; for (int i = packets.Length - 1; i >= 0; i--) { packets[i] = Assert.IsAssignableFrom<Packet>(await readHandler.ReceiveAsync()); } PubAckPacket pubAckPacket = Assert.Single(packets.OfType<PubAckPacket>()); Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId); PublishPacket publishQoS0Packet = Assert.Single(packets.OfType<PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtMostOnce)); this.AssertPacketCoreValue(publishQoS0Packet, NotificationQoS0Content); PublishPacket publishQoS1Packet = Assert.Single(packets.OfType<PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtLeastOnce)); this.AssertPacketCoreValue(publishQoS1Packet, NotificationQoS1Content); PublishPacket[] publishQoS2Packets = packets.OfType<PublishPacket>().Where(x => x.QualityOfService == QualityOfService.ExactlyOnce).Reverse().ToArray(); Assert.Equal(2, publishQoS2Packets.Length); PublishPacket publishQoS2Packet1 = publishQoS2Packets[0]; this.AssertPacketCoreValue(publishQoS2Packet1, NotificationQoS2Content); PublishPacket publishQoS2Packet2 = publishQoS2Packets[1]; this.AssertPacketCoreValue(publishQoS2Packet2, NotificationQoS2Content2); await channel.WriteAndFlushManyAsync( PubAckPacket.InResponseTo(publishQoS1Packet), PubRecPacket.InResponseTo(publishQoS2Packet1), PubRecPacket.InResponseTo(publishQoS2Packet2)); var pubRelQoS2Packet1 = Assert.IsAssignableFrom<PubRelPacket>(await readHandler.ReceiveAsync()); Assert.Equal(publishQoS2Packet1.PacketId, pubRelQoS2Packet1.PacketId); var pubRelQoS2Packet2 = Assert.IsAssignableFrom<PubRelPacket>(await readHandler.ReceiveAsync()); Assert.Equal(publishQoS2Packet2.PacketId, pubRelQoS2Packet2.PacketId); await channel.WriteAndFlushManyAsync( PubCompPacket.InResponseTo(pubRelQoS2Packet1), DisconnectPacket.Instance); // device queue still contains QoS 2 packet 2 which was PUBRECed but not PUBCOMPed. }
static async Task RunMqttServerScenarioAsync(IChannel channel, ReadListeningHandler readListener) { var connectPacket = await readListener.ReceiveAsync(DefaultTimeout) as ConnectPacket; Assert.IsNotNull(connectPacket, "Must be a Connect pkt"); // todo verify await channel.WriteAndFlushAsync(new ConnAckPacket { ReturnCode = ConnectReturnCode.Accepted, SessionPresent = true }); var subscribePacket = await readListener.ReceiveAsync(DefaultTimeout) as SubscribePacket; Assert.IsNotNull(subscribePacket); // todo verify await channel.WriteAndFlushAsync(SubAckPacket.InResponseTo(subscribePacket, QualityOfService.ExactlyOnce)); var unsubscribePacket = await readListener.ReceiveAsync(DefaultTimeout) as UnsubscribePacket; Assert.IsNotNull(unsubscribePacket); // todo verify await channel.WriteAndFlushAsync(UnsubAckPacket.InResponseTo(unsubscribePacket)); var publishQos0Packet = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket; Assert.IsNotNull(publishQos0Packet); // todo verify var publishQos1Packet = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket; Assert.IsNotNull(publishQos1Packet); // todo verify int publishQos1PacketId = GetRandomPacketId(); await channel.WriteAndFlushManyAsync( PubAckPacket.InResponseTo(publishQos1Packet), new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = publishQos1PacketId, TopicName = PublishS2CQos1Topic, Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishS2CQos1Payload)) }); var pubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as PubAckPacket; Assert.AreEqual(publishQos1PacketId, pubAckPacket.PacketId); var disconnectPacket = await readListener.ReceiveAsync(DefaultTimeout) as DisconnectPacket; Assert.IsNotNull(disconnectPacket); }
IEnumerable <TestScenarioStep> GetMqttServerScenario(Func <object> currentMessageFunc) { yield return(TestScenarioStep.MoreFeedbackExpected()); var connectPacket = Assert.IsType <ConnectPacket>(currentMessageFunc()); // todo verify yield return(TestScenarioStep.Message(new ConnAckPacket { ReturnCode = ConnectReturnCode.Accepted, SessionPresent = true })); var subscribePacket = Assert.IsType <SubscribePacket>(currentMessageFunc()); // todo verify yield return(TestScenarioStep.Message(SubAckPacket.InResponseTo(subscribePacket, QualityOfService.ExactlyOnce))); var unsubscribePacket = Assert.IsType <UnsubscribePacket>(currentMessageFunc()); // todo verify yield return(TestScenarioStep.Message(UnsubAckPacket.InResponseTo(unsubscribePacket))); var publishQos0Packet = Assert.IsType <PublishPacket>(currentMessageFunc()); // todo verify yield return(TestScenarioStep.MoreFeedbackExpected()); var publishQos1Packet = Assert.IsType <PublishPacket>(currentMessageFunc()); // todo verify int publishQos1PacketId = GetRandomPacketId(); yield return(TestScenarioStep.Messages(PubAckPacket.InResponseTo(publishQos1Packet), new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = publishQos1PacketId, TopicName = PublishS2CQos1Topic, Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishS2CQos1Payload)) })); var pubAckPacket = Assert.IsType <PubAckPacket>(currentMessageFunc()); Assert.Equal(publishQos1PacketId, pubAckPacket.PacketId); yield return(TestScenarioStep.MoreFeedbackExpected()); var disconnectPacket = Assert.IsType <DisconnectPacket>(currentMessageFunc()); }
async Task PublishToServerAsync(IChannelHandlerContext context, PublishPacket packet, string messageType) { if (!this.ConnectedToHub) { return; } PreciseTimeSpan startedTimestamp = PreciseTimeSpan.FromStart; this.ResumeReadingIfNecessary(context); using (Stream bodyStream = packet.Payload.IsReadable() ? new ReadOnlyByteBufferStream(packet.Payload, true) : null) using (IMessage message = this.messagingFactory.CreateMessage(bodyStream)) { this.ApplyRoutingConfiguration(message, packet); Util.CompleteMessageFromPacket(message, packet, this.settings); if (messageType != null) { message.Properties[this.settings.ServicePropertyPrefix + MessagePropertyNames.MessageType] = messageType; } await this.messagingServiceClient.SendAsync(message); PerformanceCounters.MessagesSentPerSecond.Increment(); } if (!this.IsInState(StateFlags.Closed)) { switch (packet.QualityOfService) { case QualityOfService.AtMostOnce: // no response necessary PerformanceCounters.InboundMessageProcessingTime.Register(startedTimestamp); break; case QualityOfService.AtLeastOnce: Util.WriteMessageAsync(context, PubAckPacket.InResponseTo(packet)) .OnFault(ShutdownOnWriteFaultAction, context); PerformanceCounters.InboundMessageProcessingTime.Register(startedTimestamp); // todo: assumes PUBACK is written out sync break; case QualityOfService.ExactlyOnce: ShutdownOnError(context, "QoS 2 is not supported."); break; default: throw new InvalidOperationException("Unexpected QoS level: " + packet.QualityOfService); } } }
private async Task OnPublish(MessageWebSocket ws, Packet packet) { var outStream = ws.OutputStream; var publishPacket = (PublishPacket)packet; if (publishPacket.Payload == null) { throw new Exception($"{nameof(SyncClient)}: Publish packet received but payload is null"); } var payload = Encoding.UTF8.GetString(publishPacket.Payload.ToArray()); this.Log($"Publish to {publishPacket.TopicName} with payload: {payload}"); switch (publishPacket.TopicName) { case "/ig_message_sync": var messageSyncPayload = JsonConvert.DeserializeObject <List <MessageSyncEventArgs> >(payload); var latest = messageSyncPayload.Last(); if (latest.SeqId > _seqId && latest.Data.Count > 0) { _seqId = latest.SeqId; if (latest.Data[0].Op != "remove") { _snapshotAt = latest.Data[0].Item.Timestamp; } } MessageReceived?.Invoke(this, messageSyncPayload); break; case "/pubsub": payload = payload.Substring(payload.IndexOf('{')); // pubsub is weird. It has a few non string bytes before the actual data. var pubsub = JsonConvert.DeserializeObject <PubsubEventArgs>(payload); if (pubsub.Data[0].Path.Contains("activity_indicator_id")) { ActivityIndicatorChanged?.Invoke(this, pubsub); } break; case "/ig_realtime_sub": payload = payload.Substring(payload.IndexOf('{')); var container = JsonConvert.DeserializeObject <JObject>(payload); var presenceEvent = container["presence_event"].ToObject <UserPresenceEventArgs>(); UserPresenceChanged?.Invoke(this, presenceEvent); break; } if (publishPacket.QualityOfService == QualityOfService.AtLeastOnce) { await WriteAndFlushPacketAsync(PubAckPacket.InResponseTo(publishPacket), outStream); } }
async Task ReceiveAndCompleteCommandAsync(IChannel clientChannel, ReadListeningHandler readHandler, IotHubConnectionStringBuilder hubConnectionStringBuilder, Device device) { var packet = Assert.IsType <PublishPacket>(await readHandler.ReceiveAsync()); Assert.Equal($"devices/{this.deviceId}/messages/devicebound", packet.TopicName); Assert.Equal(MethodContent, Encoding.UTF8.GetString(packet.Payload.ToArray())); await clientChannel.WriteAndFlushManyAsync(PubAckPacket.InResponseTo(packet), PubRecPacket.InResponseTo(packet)); var pubRelQoS2Packet2 = Assert.IsAssignableFrom <PubRelPacket>(await readHandler.ReceiveAsync()); await clientChannel.WriteAndFlushManyAsync( PubCompPacket.InResponseTo(pubRelQoS2Packet2), DisconnectPacket.Instance); await this.EnsureDeviceQueueLengthAsync(hubConnectionStringBuilder.HostName, device, 0); }
async Task GetPart2SpecificSteps(IChannel channel, ReadListeningHandler readHandler) { var packets = new Packet[2]; for (int i = packets.Length - 1; i >= 0; i--) { packets[i] = Assert.IsAssignableFrom<Packet>(await readHandler.ReceiveAsync()); } PublishPacket qos1Packet = Assert.Single(packets.OfType<PublishPacket>()); Assert.Equal(QualityOfService.AtLeastOnce, qos1Packet.QualityOfService); this.AssertPacketCoreValue(qos1Packet, Encoding.ASCII.GetString(qos1Packet.Payload.ToArray())); PubRelPacket pubRelQos2Packet = Assert.Single(packets.OfType<PubRelPacket>()); await channel.WriteAndFlushManyAsync( PubAckPacket.InResponseTo(qos1Packet), PubCompPacket.InResponseTo(pubRelQos2Packet), DisconnectPacket.Instance); }
Task SendAckAsync(IChannelHandlerContext context, PublishPacket publish) { if (Logging.IsEnabled) { Logging.Enter(this, context.Name, publish, nameof(SendAckAsync)); } try { this.ResumeReadingIfNecessary(context); return(Util.WriteMessageAsync(context, PubAckPacket.InResponseTo(publish), ShutdownOnWriteErrorHandler)); } finally { if (Logging.IsEnabled) { Logging.Exit(this, context.Name, publish, nameof(SendAckAsync)); } } }
private async void OnMessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args) { if (_pinging?.IsCancellationRequested ?? false) { return; } try { var dataReader = args.GetDataReader(); var outStream = sender.OutputStream; var loggedInUser = _instaApi.Session.LoggedInUser; Packet packet; try { packet = StandalonePacketDecoder.DecodePacket(dataReader); } catch (Exception e) { Debug.WriteLine(e); Debug.WriteLine($"{nameof(SyncClient)}: Failed to decode packet."); return; } switch (packet.PacketType) { case PacketType.CONNACK: Debug.WriteLine($"{nameof(SyncClient)}: " + packet.PacketType); var subscribePacket = new SubscribePacket( _packetId++, new SubscriptionRequest("/ig_message_sync", QualityOfService.AtMostOnce), new SubscriptionRequest("/ig_send_message_response", QualityOfService.AtMostOnce) ); await WriteAndFlushPacketAsync(subscribePacket, outStream); var unsubPacket = new UnsubscribePacket(_packetId++, "/ig_sub_iris_response"); await WriteAndFlushPacketAsync(unsubPacket, outStream); subscribePacket = new SubscribePacket(_packetId++, new SubscriptionRequest("/ig_sub_iris_response", QualityOfService.AtMostOnce)); await WriteAndFlushPacketAsync(subscribePacket, outStream); var random = new Random(); var json = new JObject( new JProperty("seq_id", _seqId), new JProperty("snapshot_at_ms", _snapshotAt.ToUnixTimeMilliseconds()), new JProperty("snapshot_app_version", "web"), new JProperty("subscription_type", "message")); var jsonBytes = GetJsonBytes(json); var irisPublishPacket = new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = _packetId++, TopicName = "/ig_sub_iris", Payload = Unpooled.CopiedBuffer(jsonBytes) }; await WriteAndFlushPacketAsync(irisPublishPacket, outStream); json = new JObject(new JProperty("unsub", new JArray($"ig/u/v1/{loggedInUser.Pk}"))); jsonBytes = GetJsonBytes(json); var pubsubPublishPacket = new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = _packetId++, TopicName = "/pubsub", Payload = Unpooled.CopiedBuffer(jsonBytes) }; await WriteAndFlushPacketAsync(pubsubPublishPacket, outStream); unsubPacket = new UnsubscribePacket(_packetId++, "/pubsub"); await WriteAndFlushPacketAsync(unsubPacket, outStream); subscribePacket = new SubscribePacket(_packetId++, new SubscriptionRequest("/pubsub", QualityOfService.AtMostOnce)); await WriteAndFlushPacketAsync(subscribePacket, outStream); json = new JObject(new JProperty("sub", new JArray($"ig/u/v1/{loggedInUser.Pk}"))); jsonBytes = GetJsonBytes(json); pubsubPublishPacket = new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = _packetId++, TopicName = "/pubsub", Payload = Unpooled.CopiedBuffer(jsonBytes) }; await WriteAndFlushPacketAsync(pubsubPublishPacket, outStream); Debug.WriteLine($"{nameof(SyncClient)}: " + packet.PacketType); _ = Task.Run(async() => { while (!_pinging.IsCancellationRequested) { try { await Task.Delay(TimeSpan.FromSeconds(8), _pinging.Token); var pingPacket = PingReqPacket.Instance; var pingBuffer = StandalonePacketEncoder.EncodePacket(pingPacket); await sender.OutputStream.WriteAsync(pingBuffer); await sender.OutputStream.FlushAsync(); } catch (TaskCanceledException) { Debug.WriteLine("Stopped pinging sync server"); return; } } }); return; case PacketType.PUBLISH: var publishPacket = (PublishPacket)packet; var payload = publishPacket.Payload.ReadString(publishPacket.Payload.ReadableBytes, Encoding.UTF8); if (publishPacket.TopicName == "/ig_message_sync") { var messageSyncPayload = JsonConvert.DeserializeObject <List <MessageSyncEventArgs> >(payload); var latest = messageSyncPayload.Last(); if (latest.SeqId > _seqId || latest.Data[0].Item.Timestamp > _snapshotAt) { _seqId = latest.SeqId; _snapshotAt = latest.Data[0].Item.Timestamp; } MessageReceived?.Invoke(this, messageSyncPayload); } Debug.WriteLine($"{nameof(SyncClient)} pub to {publishPacket.TopicName} payload: {payload}"); if (publishPacket.QualityOfService == QualityOfService.AtLeastOnce) { await WriteAndFlushPacketAsync(PubAckPacket.InResponseTo(publishPacket), outStream); } return; case PacketType.PINGRESP: Debug.WriteLine("Got pong from Sync Client"); break; default: Debug.WriteLine($"{nameof(SyncClient)}: " + packet.PacketType); break; } } catch (Exception e) { #if !DEBUG Crashes.TrackError(e); #endif Debug.WriteLine("Exception occured when processing incoming sync message."); Debug.WriteLine(e); } }
static async Task RunMqttClientScenarioAsync(IChannel channel, ReadListeningHandler readListener) { await channel.WriteAndFlushAsync(new ConnectPacket { ClientId = ClientId, Username = "******", Password = "******", WillTopicName = "last/word", WillMessage = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("oops")) }); var connAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as ConnAckPacket; Assert.IsNotNull(connAckPacket); Assert.AreEqual(ConnectReturnCode.Accepted, connAckPacket.ReturnCode); int subscribePacketId = GetRandomPacketId(); int unsubscribePacketId = GetRandomPacketId(); await channel.WriteAndFlushManyAsync( new SubscribePacket(subscribePacketId, new SubscriptionRequest(SubscribeTopicFilter1, QualityOfService.ExactlyOnce), new SubscriptionRequest(SubscribeTopicFilter2, QualityOfService.AtLeastOnce), new SubscriptionRequest("for/unsubscribe", QualityOfService.AtMostOnce)), new UnsubscribePacket(unsubscribePacketId, "for/unsubscribe")); var subAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as SubAckPacket; Assert.IsNotNull(subAckPacket); Assert.AreEqual(subscribePacketId, subAckPacket.PacketId); Assert.AreEqual(3, subAckPacket.ReturnCodes.Count); Assert.AreEqual(QualityOfService.ExactlyOnce, subAckPacket.ReturnCodes[0]); Assert.AreEqual(QualityOfService.AtLeastOnce, subAckPacket.ReturnCodes[1]); Assert.AreEqual(QualityOfService.AtMostOnce, subAckPacket.ReturnCodes[2]); var unsubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as UnsubAckPacket; Assert.IsNotNull(unsubAckPacket); Assert.AreEqual(unsubscribePacketId, unsubAckPacket.PacketId); int publishQoS1PacketId = GetRandomPacketId(); await channel.WriteAndFlushManyAsync( new PublishPacket(QualityOfService.AtMostOnce, false, false) { TopicName = PublishC2STopic, Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishC2SQos0Payload)) }, new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = publishQoS1PacketId, TopicName = PublishC2SQos1Topic, Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishC2SQos1Payload)) }); //new PublishPacket(QualityOfService.AtLeastOnce, false, false) { TopicName = "feedback/qos/One", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("QoS 1 test. Different data length.")) }); var pubAckPacket = await readListener.ReceiveAsync(DefaultTimeout) as PubAckPacket; Assert.IsNotNull(pubAckPacket); Assert.AreEqual(publishQoS1PacketId, pubAckPacket.PacketId); var publishPacket = await readListener.ReceiveAsync(DefaultTimeout) as PublishPacket; Assert.IsNotNull(publishPacket); Assert.AreEqual(QualityOfService.AtLeastOnce, publishPacket.QualityOfService); Assert.AreEqual(PublishS2CQos1Topic, publishPacket.TopicName); Assert.AreEqual(PublishS2CQos1Payload, publishPacket.Payload.ToString(Encoding.UTF8)); await channel.WriteAndFlushManyAsync( PubAckPacket.InResponseTo(publishPacket), DisconnectPacket.Instance); }
Task SendAckAsync(IChannelHandlerContext context, PublishPacket publish) { this.ResumeReadingIfNecessary(context); return(Util.WriteMessageAsync(context, PubAckPacket.InResponseTo(publish), ShutdownOnWriteErrorHandler)); }
private async Task OnPacketReceived(Packet msg) { if (!Running) { return; } var writer = _outboundWriter; try { switch (msg.PacketType) { case PacketType.CONNACK: this.Log("Received CONNACK"); await SubscribeForDM(); await RealtimeSub(); await PubSub(); if (SnapshotAt != null && SeqId <= 0) { await IrisSub(); } StartKeepAliveLoop(); break; case PacketType.PUBLISH: this.Log("Received PUBLISH"); var publishPacket = (PublishPacket)msg; if (publishPacket.Payload == null) { throw new Exception($"{nameof(RealtimeClient)}: Publish packet received but payload is null"); } if (publishPacket.QualityOfService == QualityOfService.AtLeastOnce) { await FbnsPacketEncoder.EncodePacket(PubAckPacket.InResponseTo(publishPacket), writer); } var payload = DecompressPayload(publishPacket.Payload); var json = await GetJsonFromThrift(payload); this.Log($"MQTT json: {json}"); if (string.IsNullOrEmpty(json)) { break; } try { Debug.WriteLine(""); Debug.WriteLine($"Unknown topic received:{msg.PacketType} : {publishPacket.TopicName} : {json}"); Debug.WriteLine(""); Debug.WriteLine(json); switch (publishPacket.TopicName) { case "150": break; case "133": // /ig_send_message_response try { Responses.AddItem(JsonConvert.DeserializeObject <InstaDirectRespondResponse>(json)); } catch { try { var o = JsonConvert.DeserializeObject <InstaDirectRespondV2Response>(json); Responses.AddItem(new InstaDirectRespondResponse { Action = o.Action, Message = o.Message, Status = o.Status, StatusCode = o.StatusCode, Payload = o.Payload[0] }); } catch { } } break; case "88": { var obj = JsonConvert.DeserializeObject <InstaRealtimeRespondResponse>(json); if (obj?.Data?.Length > 0) { var typing = new List <InstaRealtimeTypingEventArgs>(); var dm = new List <InstaDirectInboxItem>(); for (int i = 0; i < obj.Data.Length; i++) { var item = obj.Data[i]; if (item != null) { if (item.IsTyping) { var typingResponse = JsonConvert.DeserializeObject <InstaRealtimeTypingResponse>(item.Value); if (typingResponse != null) { try { var tr = new InstaRealtimeTypingEventArgs { SenderId = typingResponse.SenderId, ActivityStatus = typingResponse.ActivityStatus, RealtimeOp = item.Op, RealtimePath = item.Path, TimestampUnix = typingResponse.Timestamp, Timestamp = DateTimeHelper.FromUnixTimeMiliSeconds(typingResponse.Timestamp), Ttl = typingResponse.Ttl }; typing.Add(tr); } catch { } } } else if (item.IsThreadItem || item.IsThreadParticipants) { if (item.HasItemInValue) { var directItemResponse = JsonConvert.DeserializeObject <InstaDirectInboxItemResponse>(item.Value); if (directItemResponse != null) { try { var dI = ConvertersFabric.Instance.GetDirectThreadItemConverter(directItemResponse).Convert(); dI.RealtimeOp = item.Op; dI.RealtimePath = item.Path; dm.Add(dI); } catch { } } } else { var dI = new InstaDirectInboxItem { RealtimeOp = item.Op, RealtimePath = item.Path, ItemId = item.Value }; dm.Add(dI); } } } } if (typing.Count > 0) { OnTypingChanged(typing); } if (dm.Count > 0) { OnDirectItemChanged(dm); } } } break; } } catch { } break; case PacketType.PUBACK: this.Log("Received PUBACK"); break; case PacketType.PINGRESP: this.Log("Received PINGRESP"); break; default: Debug.WriteLine($"Unknown topic received:{msg.PacketType}"); break; } } catch (Exception e) { DebugLogger.LogExceptionX(e); } }
async Task GetPart1SpecificSteps(IChannel channel, ReadListeningHandler readHandler) { int publishQoS1PacketId = 1003; await channel.WriteAndFlushManyAsync( new PublishPacket(QualityOfService.AtMostOnce, false, false) { //TopicName = string.Format("devices/{0}/messages/log/verbose/", clientId), TopicName = $"devices/{this.clientId}/messages/events", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry-QoS0\"}")) }, new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = publishQoS1PacketId, TopicName = $"devices/{this.clientId}/messages/events", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry\"}")) }); Packet[] packets = (await Task.WhenAll(Enumerable.Repeat(0, 6).Select(_ => readHandler.ReceiveAsync()))) .Select(Assert.IsAssignableFrom <Packet>) .ToArray(); PubAckPacket pubAckPacket = Assert.Single(packets.OfType <PubAckPacket>()); Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId); PublishPacket publishQoS0Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtMostOnce)); this.AssertPacketCoreValue(publishQoS0Packet, "tips", NotificationQoS0Content); PublishPacket[] publishQoS1Packets = packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtLeastOnce).ToArray(); Assert.Equal(2, publishQoS1Packets.Length); var qos1Notification = Assert.Single(publishQoS1Packets, x => x.TopicName.EndsWith("firmware-update")); this.AssertPacketCoreValue(qos1Notification, "firmware-update", NotificationQoS1Content); var methodCall = Assert.Single(publishQoS1Packets, x => x.TopicName.EndsWith("commands")); this.AssertPacketCoreValue(methodCall, "commands", MethodCallContent); PublishPacket[] publishQoS2Packets = packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.ExactlyOnce).ToArray(); Assert.Equal(2, publishQoS2Packets.Length); PublishPacket publishQoS2Packet1 = publishQoS2Packets[0]; this.AssertPacketCoreValue(publishQoS2Packet1, "critical-alert", NotificationQoS2Content); PublishPacket publishQoS2Packet2 = publishQoS2Packets[1]; this.AssertPacketCoreValue(publishQoS2Packet2, string.Empty, NotificationQoS2Content2); await channel.WriteAndFlushManyAsync( PubAckPacket.InResponseTo(qos1Notification), PubAckPacket.InResponseTo(methodCall), PubRecPacket.InResponseTo(publishQoS2Packet1), PubRecPacket.InResponseTo(publishQoS2Packet2)); var pubRelQoS2Packet1 = Assert.IsAssignableFrom <PubRelPacket>(await readHandler.ReceiveAsync()); Assert.Equal(publishQoS2Packet1.PacketId, pubRelQoS2Packet1.PacketId); var pubRelQoS2Packet2 = Assert.IsAssignableFrom <PubRelPacket>(await readHandler.ReceiveAsync()); Assert.Equal(publishQoS2Packet2.PacketId, pubRelQoS2Packet2.PacketId); await channel.WriteAndFlushManyAsync( PubCompPacket.InResponseTo(pubRelQoS2Packet1), DisconnectPacket.Instance); // device queue still contains QoS 2 packet 2 which was PUBRECed but not PUBCOMPed. }
private async Task OnPacketReceived(Packet msg) { if (!Running) { return; } var writer = _outboundWriter; try { switch (msg.PacketType) { case PacketType.CONNACK: this.Log("Received CONNACK"); ConnectionData.UpdateAuth(((FbnsConnAckPacket)msg).Authentication); await RegisterMqttClient(); break; case PacketType.PUBLISH: this.Log("Received PUBLISH"); var publishPacket = (PublishPacket)msg; if (publishPacket.Payload == null) { throw new Exception($"{nameof(PushClient)}: Publish packet received but payload is null"); } if (publishPacket.QualityOfService == QualityOfService.AtLeastOnce) { await FbnsPacketEncoder.EncodePacket(PubAckPacket.InResponseTo(publishPacket), writer); } var payload = DecompressPayload(publishPacket.Payload); var json = Encoding.UTF8.GetString(payload); this.Log($"MQTT json: {json}"); switch (Enum.Parse(typeof(TopicIds), publishPacket.TopicName)) { case TopicIds.Message: try { var message = JsonConvert.DeserializeObject <PushReceivedEventArgs>(json); message.Json = json; if (message.NotificationContent.CollapseKey == "direct_v2_message") { MessageReceived?.Invoke(this, message); } } catch (Exception e) { // If something wrong happens here we don't need to shut down the whole push client DebugLogger.LogException(e); } break; case TopicIds.RegResp: await OnRegisterResponse(json); StartKeepAliveLoop(); break; default: this.Log($"Unknown topic received: {publishPacket.TopicName}"); break; } break; case PacketType.PUBACK: this.Log("Received PUBACK"); _waitingForPubAck = false; break; case PacketType.PINGRESP: this.Log("Received PINGRESP"); break; default: throw new NotSupportedException($"Packet type {msg.PacketType} is not supported."); } } catch (Exception e) { DebugLogger.LogException(e); } }
IEnumerable <TestScenarioStep> GetMqttClientScenario(Func <object> currentMessageFunc) { yield return(TestScenarioStep.Message(new ConnectPacket { ClientId = ClientId, Username = "******", Password = "******", WillTopicName = "last/word", WillMessage = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("oops")) })); var connAckPacket = Assert.IsType <ConnAckPacket>(currentMessageFunc()); Assert.Equal(ConnectReturnCode.Accepted, connAckPacket.ReturnCode); int subscribePacketId = GetRandomPacketId(); int unsubscribePacketId = GetRandomPacketId(); yield return(TestScenarioStep.Messages( new SubscribePacket(subscribePacketId, new SubscriptionRequest(SubscribeTopicFilter1, QualityOfService.ExactlyOnce), new SubscriptionRequest(SubscribeTopicFilter2, QualityOfService.AtLeastOnce), new SubscriptionRequest("for/unsubscribe", QualityOfService.AtMostOnce)), new UnsubscribePacket(unsubscribePacketId, "for/unsubscribe"))); var subAckPacket = Assert.IsType <SubAckPacket>(currentMessageFunc()); Assert.Equal(subscribePacketId, subAckPacket.PacketId); Assert.Equal(3, subAckPacket.ReturnCodes.Count); Assert.Equal(QualityOfService.ExactlyOnce, subAckPacket.ReturnCodes[0]); Assert.Equal(QualityOfService.AtLeastOnce, subAckPacket.ReturnCodes[1]); Assert.Equal(QualityOfService.AtMostOnce, subAckPacket.ReturnCodes[2]); yield return(TestScenarioStep.MoreFeedbackExpected()); var unsubAckPacket = Assert.IsType <UnsubAckPacket>(currentMessageFunc()); Assert.Equal(unsubscribePacketId, unsubAckPacket.PacketId); int publishQoS1PacketId = GetRandomPacketId(); yield return(TestScenarioStep.Messages( new PublishPacket(QualityOfService.AtMostOnce, false, false) { TopicName = PublishC2STopic, Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishC2SQos0Payload)) }, new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = publishQoS1PacketId, TopicName = PublishC2SQos1Topic, Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(PublishC2SQos1Payload)) })); //new PublishPacket(QualityOfService.AtLeastOnce, false, false) { TopicName = "feedback/qos/One", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("QoS 1 test. Different data length.")) }); var pubAckPacket = Assert.IsType <PubAckPacket>(currentMessageFunc()); Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId); yield return(TestScenarioStep.MoreFeedbackExpected()); var publishPacket = Assert.IsType <PublishPacket>(currentMessageFunc()); Assert.Equal(QualityOfService.AtLeastOnce, publishPacket.QualityOfService); Assert.Equal(PublishS2CQos1Topic, publishPacket.TopicName); Assert.Equal(PublishS2CQos1Payload, Encoding.UTF8.GetString(publishPacket.Payload.ToArray())); yield return(TestScenarioStep.Messages( PubAckPacket.InResponseTo(publishPacket), DisconnectPacket.Instance)); }
static IEnumerable <TestScenarioStep> GetClientScenario(Func <object> currentMessageFunc, string iotHubName, string clientId, string password) { yield return(TestScenarioStep.Write(new ConnectPacket { ClientId = clientId, HasUsername = true, Username = iotHubName + "/" + clientId, HasPassword = true, Password = password, KeepAliveInSeconds = 120, HasWill = true, WillTopicName = "last/word", WillMessage = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("oops")) })); var connAckPacket = Assert.IsType <ConnAckPacket>(currentMessageFunc()); Assert.Equal(ConnectReturnCode.Accepted, connAckPacket.ReturnCode); int subscribePacketId = GetRandomPacketId(); yield return(TestScenarioStep.Write(new SubscribePacket { PacketId = subscribePacketId, Requests = new[] { new SubscriptionRequest(string.Format("devices/{0}/messages/devicebound/#", clientId), QualityOfService.ExactlyOnce) } })); var subAckPacket = Assert.IsType <SubAckPacket>(currentMessageFunc()); Assert.Equal(subscribePacketId, subAckPacket.PacketId); Assert.Equal(1, subAckPacket.ReturnCodes.Count); Assert.Equal(QualityOfService.ExactlyOnce, subAckPacket.ReturnCodes[0]); int publishQoS1PacketId = GetRandomPacketId(); yield return(TestScenarioStep.Write( new PublishPacket(QualityOfService.AtMostOnce, false, false) { //TopicName = string.Format("devices/{0}/messages/log/verbose/", clientId), TopicName = string.Format("devices/{0}/messages/events", clientId), Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry-QoS0\"}")) }, new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = publishQoS1PacketId, TopicName = string.Format("devices/{0}/messages/events", clientId), Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry\"}")) })); var packets = new Packet[4]; for (int i = packets.Length - 1; i >= 0; i--) { packets[i] = Assert.IsAssignableFrom <Packet>(currentMessageFunc()); if (i > 0) { yield return(TestScenarioStep.ReadMore()); } } PubAckPacket pubAckPacket = Assert.Single(packets.OfType <PubAckPacket>()); Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId); PublishPacket publishQoS0Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtMostOnce)); //Assert.Equal(string.Format("devices/{0}/messages/devicebound/tips", clientId), publishQoS0Packet.TopicName); Assert.Equal(string.Format("devices/{0}/messages/devicebound", clientId), publishQoS0Packet.TopicName); Assert.Equal(NotificationQoS0Content, Encoding.UTF8.GetString(publishQoS0Packet.Payload.ToArray())); PublishPacket publishQoS1Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtLeastOnce)); //Assert.Equal(string.Format("devices/{0}/messages/devicebound/firmware-update", clientId), publishQoS1Packet.TopicName); Assert.Equal(string.Format("devices/{0}/messages/devicebound", clientId), publishQoS1Packet.TopicName); Assert.Equal(NotificationQoS1Content, Encoding.UTF8.GetString(publishQoS1Packet.Payload.ToArray())); PublishPacket publishQoS2Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.ExactlyOnce)); //Assert.Equal(string.Format("devices/{0}/messages/devicebound/critical-alert", clientId), publishQoS2Packet.TopicName); Assert.Equal(string.Format("devices/{0}/messages/devicebound", clientId), publishQoS2Packet.TopicName); Assert.Equal(NotificationQoS2Content, Encoding.UTF8.GetString(publishQoS2Packet.Payload.ToArray())); yield return(TestScenarioStep.Write( PubAckPacket.InResponseTo(publishQoS1Packet), PubRecPacket.InResponseTo(publishQoS2Packet))); var pubRelQoS2Packet = Assert.IsAssignableFrom <PubRelPacket>(currentMessageFunc()); Assert.Equal(publishQoS2Packet.PacketId, pubRelQoS2Packet.PacketId); yield return(TestScenarioStep.Write( false, // it is a final step and we do not expect response PubCompPacket.InResponseTo(pubRelQoS2Packet), DisconnectPacket.Instance)); }
private async Task OnPacketReceived(Packet msg) { try { switch (msg.PacketType) { case PacketType.CONNACK: Log($"[{_instaApi.GetLoggedUser().UserName}] " + "Received CONNACK"); ConnectionData.UpdateAuth(((FbnsConnAckPacket)msg).Authentication); await RegisterMqttClient(); break; case PacketType.PUBLISH: Log($"[{_instaApi.GetLoggedUser().UserName}] " + "Received PUBLISH"); var publishPacket = (PublishPacket)msg; if (publishPacket.Payload == null) { throw new Exception($"{nameof(PushClient)}: Publish packet received but payload is null"); } if (publishPacket.QualityOfService == QualityOfService.AtLeastOnce) { await FbnsPacketEncoder.EncodePacket(PubAckPacket.InResponseTo(publishPacket), _outboundWriter); } var payload = DecompressPayload(publishPacket.Payload); var json = Encoding.UTF8.GetString(payload); Log($"[{_instaApi.GetLoggedUser().UserName}] " + $"MQTT json: {json}"); switch (Enum.Parse(typeof(TopicIds), publishPacket.TopicName)) { case TopicIds.Message: var message = JsonConvert.DeserializeObject <PushReceivedEventArgs>(json); message.Json = json; message.InstaApi = _instaApi; MessageReceived?.Invoke(this, message); break; case TopicIds.RegResp: await OnRegisterResponse(json); StartKeepAliveLoop(); break; default: Log($"[{_instaApi.GetLoggedUser().UserName}] " + $"Unknown topic received: {publishPacket.TopicName}"); break; } break; case PacketType.PUBACK: Log($"[{_instaApi.GetLoggedUser().UserName}] " + "Received PUBACK"); _waitingForPubAck = false; break; // todo: PingResp never arrives even though data was received. Decoder problem? case PacketType.PINGRESP: Log($"[{_instaApi.GetLoggedUser().UserName}] " + "Received PINGRESP"); break; default: return; //throw new NotSupportedException($"Packet type {msg.PacketType} is not supported."); } } catch (Exception ex) { PrintException("SendPing", ex); Shutdown(); } }
protected override async void ChannelRead0(IChannelHandlerContext ctx, Packet msg) { try { _context = ctx; // Save context for manual Ping later switch (msg.PacketType) { case PacketType.CONNACK: Debug.WriteLine($"{nameof(PushClient)}:\tCONNACK received."); ConnectionData.UpdateAuth(((FbnsConnAckPacket)msg).Authentication); RegisterMqttClient(ctx); break; case PacketType.PUBLISH: Debug.WriteLine($"{nameof(PushClient)}:\tPUBLISH received."); var publishPacket = (PublishPacket)msg; if (publishPacket.QualityOfService == QualityOfService.AtLeastOnce) { await ctx.WriteAndFlushAsync(PubAckPacket.InResponseTo(publishPacket)); } var payload = DecompressPayload(publishPacket.Payload); var json = Encoding.UTF8.GetString(payload); Debug.WriteLine($"{nameof(PushClient)}:\tMQTT json: {json}"); switch (Enum.Parse(typeof(TopicIds), publishPacket.TopicName)) { case TopicIds.Message: var message = JsonConvert.DeserializeObject <PushReceivedEventArgs>(json); message.Json = json; OnMessageReceived(message); break; case TopicIds.RegResp: OnRegisterResponse(json); try { await _context.Executor.Schedule(KeepAliveLoop, TimeSpan.FromSeconds(KEEP_ALIVE - 60)); } catch (TaskCanceledException) { // pass } break; default: Debug.WriteLine($"Unknown topic received: {publishPacket.TopicName}", "Warning"); break; } break; case PacketType.PUBACK: Debug.WriteLine($"{nameof(PushClient)}:\tPUBACK received."); _waitingForPubAck = false; break; // todo: PingResp never arrives even though data was received. Decoder problem? case PacketType.PINGRESP: Debug.WriteLine($"{nameof(PushClient)}:\tPINGRESP received."); break; default: throw new NotSupportedException($"Packet type {msg.PacketType} is not supported."); } } catch (Exception e) { // Something went wrong with Push client. Shutting down. #if !DEBUG Crashes.TrackError(e); #endif await Shutdown().ConfigureAwait(false); } }
IEnumerable <TestScenarioStep> GetPart1SpecificSteps(Func <object> currentMessageFunc) { int publishQoS1PacketId = GetRandomPacketId(); yield return(TestScenarioStep.Write( new PublishPacket(QualityOfService.AtMostOnce, false, false) { //TopicName = string.Format("devices/{0}/messages/log/verbose/", clientId), TopicName = $"devices/{this.clientId}/messages/events", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry-QoS0\"}")) }, new PublishPacket(QualityOfService.AtLeastOnce, false, false) { PacketId = publishQoS1PacketId, TopicName = $"devices/{this.clientId}/messages/events", Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry\"}")) })); var packets = new Packet[5]; for (int i = packets.Length - 1; i >= 0; i--) { packets[i] = Assert.IsAssignableFrom <Packet>(currentMessageFunc()); if (i > 0) { yield return(TestScenarioStep.ReadMore()); } } PubAckPacket pubAckPacket = Assert.Single(packets.OfType <PubAckPacket>()); Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId); PublishPacket publishQoS0Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtMostOnce)); this.AssertPacketCoreValue(publishQoS0Packet, NotificationQoS0Content); PublishPacket publishQoS1Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtLeastOnce)); this.AssertPacketCoreValue(publishQoS1Packet, NotificationQoS1Content); PublishPacket[] publishQoS2Packets = packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.ExactlyOnce).Reverse().ToArray(); Assert.Equal(2, publishQoS2Packets.Length); PublishPacket publishQoS2Packet1 = publishQoS2Packets[0]; this.AssertPacketCoreValue(publishQoS2Packet1, NotificationQoS2Content); PublishPacket publishQoS2Packet2 = publishQoS2Packets[1]; this.AssertPacketCoreValue(publishQoS2Packet2, NotificationQoS2Content2); yield return(TestScenarioStep.Write( PubAckPacket.InResponseTo(publishQoS1Packet), PubRecPacket.InResponseTo(publishQoS2Packet1), PubRecPacket.InResponseTo(publishQoS2Packet2))); var pubRelQoS2Packet1 = Assert.IsAssignableFrom <PubRelPacket>(currentMessageFunc()); Assert.Equal(publishQoS2Packet1.PacketId, pubRelQoS2Packet1.PacketId); yield return(TestScenarioStep.ReadMore()); var pubRelQoS2Packet2 = Assert.IsAssignableFrom <PubRelPacket>(currentMessageFunc()); Assert.Equal(publishQoS2Packet2.PacketId, pubRelQoS2Packet2.PacketId); yield return(TestScenarioStep.Write( false, // it is a final step and we do not expect response PubCompPacket.InResponseTo(pubRelQoS2Packet1), DisconnectPacket.Instance)); // device queue still contains QoS 2 packet 2 which was PUBRECed but not PUBCOMPed. }