private void Publish(MqttQualityOfService QoS) { ManualResetEvent Done = new ManualResetEvent(false); ManualResetEvent Error = new ManualResetEvent(false); this.Test_01_Connect(); this.client.OnContentReceived += (sender, e) => { string s = System.Text.Encoding.UTF8.GetString(e.Data); if (s == "Hello world.") { Done.Set(); } else { Error.Set(); } }; this.client.SUBSCRIBE("/Waher/IoT/Test", QoS); try { this.client.PUBLISH("/Waher/IoT/Test", QoS, false, System.Text.Encoding.UTF8.GetBytes("Hello world.")); Assert.AreEqual(0, WaitHandle.WaitAny(new WaitHandle[] { Done, Error }, 10000), "Content not published correctly."); } finally { this.client.UNSUBSCRIBE("/Waher/IoT/Test"); } }
/// <summary> /// Sets properties and attributes of class in accordance with XML definition. /// </summary> /// <param name="Definition">XML definition</param> public override Task FromXml(XmlElement Definition) { this.topic = XML.Attribute(Definition, "topic"); this.qos = (MqttQualityOfService)XML.Attribute(Definition, "qos", MqttQualityOfService.AtMostOnce); return(Task.CompletedTask); }
protected PubSubAttribute(string topic, MqttQualityOfService qoS, string logger, MqttQualityOfService loggerQoS) { Topic = topic; QoS = qoS; LoggerQoS = loggerQoS; Logger = logger; }
IEnumerable <Subscription> GetSubscriptions(byte[] bytes, int headerLength) { if (bytes.Length - headerLength < 4) //At least 4 bytes required on payload: MSB, LSB, Topic Filter, Requests QoS { throw new MqttProtocolViolationException(ClientProperties.SubscribeFormatter_MissingTopicFilterQosPair); } int index = headerLength; do { string topicFilter = bytes.GetString(index, out index); if (!topicEvaluator.IsValidTopicFilter(topicFilter)) { throw new MqttException(ClientProperties.SubscribeFormatter_InvalidTopicFilter(topicFilter)); } byte requestedQosByte = bytes.Byte(index); if (!Enum.IsDefined(typeof(MqttQualityOfService), requestedQosByte)) { throw new MqttProtocolViolationException(ClientProperties.Formatter_InvalidQualityOfService); } MqttQualityOfService requestedQos = (MqttQualityOfService)requestedQosByte; yield return(new Subscription(topicFilter, requestedQos)); index++; } while(bytes.Length - index + 1 >= 2); }
public async Task PublishAsync(MqttApplicationMessage message, MqttQualityOfService qos, bool retain = false) { if (disposed) { throw new ObjectDisposedException(GetType().FullName); } try { ushort?packetId = qos == MqttQualityOfService.AtMostOnce ? null : (ushort?)packetIdProvider.GetPacketId(); var publish = new Publish(message.Topic, qos, retain, duplicated: false, packetId: packetId) { Payload = message.Payload }; var senderFlow = flowProvider.GetFlow <PublishSenderFlow> (); await clientSender.Run(async() => { await senderFlow.SendPublishAsync(Id, publish, Channel) .ConfigureAwait(continueOnCapturedContext: false); }).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) { Close(ex); throw; } }
/// <summary> /// Initializes a new instance of the <see cref="MqttLastWill" /> class, /// specifying the topic to pusblish the last will message to, the Quality of Service (QoS) /// to use, if the message should be sent as a retained message and also the content of the will message /// to publish /// </summary> /// <param name="topic">Topic to publish the last will message to</param> /// <param name="qualityOfService"> /// Quality of Service (QoS) to use when publishing the last will message. /// See <see cref="MqttQualityOfService" /> for more details about the QoS meanings /// </param> /// <param name="retain">Specifies if the message should be retained or not</param> /// <param name="payload">Payload of the will message to publish</param> public MqttLastWill(string topic, MqttQualityOfService qualityOfService, bool retain, byte[] payload) { Topic = topic; QualityOfService = qualityOfService; Retain = retain; Payload = payload; }
public async Task SendPublishAsync(string clientId, Publish message, IMqttChannel <IPacket> channel, PendingMessageStatus status = PendingMessageStatus.PendingToSend) { if (channel == null || !channel.IsConnected) { SaveMessage(message, clientId, PendingMessageStatus.PendingToSend); return; } MqttQualityOfService qos = configuration.GetSupportedQos(message.QualityOfService); if (qos != MqttQualityOfService.AtMostOnce && status == PendingMessageStatus.PendingToSend) { SaveMessage(message, clientId, PendingMessageStatus.PendingToAcknowledge); } await channel.SendAsync(message); if (qos == MqttQualityOfService.AtLeastOnce) { await MonitorAckAsync <PublishAck>(message, clientId, channel); } else if (qos == MqttQualityOfService.ExactlyOnce) { await MonitorAckAsync <PublishReceived>(message, clientId, channel); await channel .ReceiverStream .ObserveOn(NewThreadScheduler.Default) .OfType <PublishComplete>() .FirstOrDefaultAsync(x => x.PacketId == message.PacketId.Value); } }
/// <summary> /// Initializes a new instance of the <see cref="MqttLastWill" /> class, /// specifying the topic to pusblish the last will message to, the Quality of Service (QoS) /// to use, if the message should be sent as a retained message and also the content of the will message /// to publish /// </summary> /// <param name="topic">Topic to publish the last will message to</param> /// <param name="qualityOfService"> /// Quality of Service (QoS) to use when publishing the last will message. /// See <see cref="MqttQualityOfService" /> for more details about the QoS meanings /// </param> /// <param name="retain">Specifies if the message should be retained or not</param> /// <param name="message">Content of the will message to publish</param> public MqttLastWill(string topic, MqttQualityOfService qualityOfService, bool retain, string message) { Topic = topic; QualityOfService = qualityOfService; Retain = retain; Message = message; }
/// <summary> /// Subscribe an action to a topic /// </summary> /// <param name="topic"></param> /// <param name="action"></param> /// <param name="qoS"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public Guid SubscribeToTopic <T>(string topic, Action <T> action, MqttQualityOfService qoS = MqttQualityOfService.ExactlyOnce) where T : class, new() { // Create a new id for the action var guid = Guid.NewGuid(); var id = guid.ToString(); // Helper variables to assess topics with wildcards correctly Func <string, string, bool> condition; string sanitizedTopic; // Does the topic contain a wildcard? if (_containsWildcards(topic)) { // Convert the mqtt wildcards with proper regex terms sanitizedTopic = _replaceWildCards(topic); // To compare those terms use the Regex.IsMatch functionality condition = Regex.IsMatch; } else { // If the topic does not contain any mqtt wildcards, than it can stay as it is sanitizedTopic = topic; // To compare the topics, use regular string comparision condition = (key, topic) => key.Equals(topic); } // If there was not prior subscription to that topic, subscribe for that topic at the mqtt message broker if (!_consumers.Keys.Any(key => condition(key, sanitizedTopic))) { _bus.SubscribeAsync(sanitizedTopic, qoS); } // Get the list of actions that belong to that topic if (!_consumers.Keys.Any(key => condition(key, sanitizedTopic))) { _consumers[sanitizedTopic] = new Dictionary <string, Action <byte[]> >(); } // Add the new action // The action of the caller is wrapped in an action that does the casting of the message _consumers[sanitizedTopic][id] = bytes => { T message = null; try { var jsonString = Utf8Encoding.GetString(bytes); message = JsonConvert.DeserializeObject <T>(jsonString); } catch (Exception e) { // ignore } // Execute the callers action with the message as parameter action(message); }; return(guid); }
/// <summary> /// Manages an MQTT connection. Implements MQTT v3.1.1, as defined in /// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html /// </summary> /// <param name="Host">Host name or IP address of MQTT server.</param> /// <param name="Port">Port to connect to.</param> /// <param name="Tls">If TLS is used to encrypt communication.</param> /// <param name="UserName">User Name</param> /// <param name="Password">Password</param> /// <param name="WillTopic">Topic to publish the last will and testament, in case the connection drops unexpectedly.</param> /// <param name="WillQoS">Quality of Service of last will and testament, in case the connection drops unexpectedly.</param> /// <param name="WillRetain">If last will and testament should be retained, in case the connection drops unexpectedly.</param> /// <param name="WillData">Data of last will and testament, in case the connection drops unexpectedly.</param> /// <param name="Sniffers">Sniffers to use.</param> public MqttClient(string Host, int Port, bool Tls, string UserName, string Password, string WillTopic, MqttQualityOfService WillQoS, bool WillRetain, byte[] WillData, params ISniffer[] Sniffers) : base(Sniffers) { this.host = Host; this.port = Port; this.tls = Tls; this.userName = UserName; this.password = Password; #if !WINDOWS_UWP this.clientCertificate = null; #endif this.state = MqttState.Offline; this.will = !string.IsNullOrEmpty(WillTopic) && WillData != null; this.willTopic = WillTopic; this.willQoS = WillQoS; this.willRetain = WillRetain; this.willData = WillData; if (this.will && this.willData.Length > 65535) { throw new ArgumentException("Will data too large.", nameof(WillData)); } Task.Run(() => this.BeginConnect()); }
/// <summary> /// Publish a message to the mqtt message broker. /// </summary> /// <param name="topic"></param> /// <param name="message"></param> /// <param name="qoS"></param> /// <typeparam name="T"></typeparam> public void Publish <T>(string topic, T message, MqttQualityOfService qoS = MqttQualityOfService.ExactlyOnce) where T : class { var jsonString = JsonConvert.SerializeObject(message); var applicationMessage = new MqttApplicationMessage(topic, Utf8Encoding.GetBytes(jsonString)); _bus.PublishAsync(applicationMessage, qoS); }
public Publish(string topic, MqttQualityOfService qualityOfService, bool retain, bool duplicated, ushort?packetId = null) { QualityOfService = qualityOfService; Duplicated = duplicated; Retain = retain; Topic = topic; PacketId = packetId; }
public async Task SubscribeAsync(string topicFilter, MqttQualityOfService qos) { if (disposed) { throw new ObjectDisposedException(GetType().FullName); } try { var packetId = packetIdProvider.GetPacketId(); var subscribe = new Subscribe(packetId, new Subscription(topicFilter, qos)); var ack = default(SubscribeAck); var subscribeTimeout = TimeSpan.FromSeconds(configuration.WaitTimeoutSecs); await SendPacketAsync(subscribe) .ConfigureAwait(continueOnCapturedContext: false); ack = await packetListener .PacketStream .ObserveOn(NewThreadScheduler.Default) .OfType <SubscribeAck> () .FirstOrDefaultAsync(x => x.PacketId == packetId) .Timeout(subscribeTimeout); if (ack == null) { var message = string.Format(Properties.Resources.Client_SubscriptionDisconnected, Id, topicFilter); tracer.Error(message); throw new MqttClientException(message); } if (ack.ReturnCodes.FirstOrDefault() == SubscribeReturnCode.Failure) { var message = string.Format(Properties.Resources.Client_SubscriptionRejected, Id, topicFilter); tracer.Error(message); throw new MqttClientException(message); } } catch (TimeoutException timeEx) { Close(timeEx); var message = string.Format(Properties.Resources.Client_SubscribeTimeout, Id, topicFilter); throw new MqttClientException(message, timeEx); } catch (MqttClientException clientEx) { Close(clientEx); throw; } catch (Exception ex) { Close(ex); var message = string.Format(Properties.Resources.Client_SubscribeError, Id, topicFilter); throw new MqttClientException(message, ex); } }
public async Task when_subscribing_topic_with_retain_message_then_retained_is_sent() { MqttConfiguration configuration = new MqttConfiguration { MaximumQualityOfService = MqttQualityOfService.AtLeastOnce }; Mock <IMqttTopicEvaluator> topicEvaluator = new Mock <IMqttTopicEvaluator>(); Mock <IRepository <ClientSession> > sessionRepository = new Mock <IRepository <ClientSession> >(); IPacketIdProvider packetIdProvider = Mock.Of <IPacketIdProvider>(); Mock <IRepository <RetainedMessage> > retainedMessageRepository = new Mock <IRepository <RetainedMessage> >(); Mock <IPublishSenderFlow> senderFlow = new Mock <IPublishSenderFlow>(); string clientId = Guid.NewGuid().ToString(); ClientSession session = new ClientSession(clientId, clean: false); sessionRepository.Setup(r => r.Read(It.IsAny <string>())).Returns(session); MqttQualityOfService fooQoS = MqttQualityOfService.AtLeastOnce; string fooTopic = "test/foo/#"; Subscription fooSubscription = new Subscription(fooTopic, fooQoS); string retainedTopic = "test/foo/bar"; MqttQualityOfService retainedQoS = MqttQualityOfService.ExactlyOnce; byte[] retainedPayload = Encoding.UTF8.GetBytes("Retained Message Test"); List <RetainedMessage> retainedMessages = new List <RetainedMessage> { new RetainedMessage(retainedTopic, retainedQoS, retainedPayload) }; topicEvaluator.Setup(e => e.IsValidTopicFilter(It.IsAny <string>())).Returns(true); topicEvaluator.Setup(e => e.Matches(It.IsAny <string>(), It.IsAny <string>())).Returns(true); retainedMessageRepository.Setup(r => r.ReadAll()).Returns(retainedMessages.AsQueryable()); ushort packetId = (ushort)new Random().Next(0, ushort.MaxValue); Subscribe subscribe = new Subscribe(packetId, fooSubscription); Mock <IMqttChannel <IPacket> > channel = new Mock <IMqttChannel <IPacket> >(); Mock <IConnectionProvider> connectionProvider = new Mock <IConnectionProvider>(); connectionProvider .Setup(p => p.GetConnection(It.Is <string>(c => c == clientId))) .Returns(channel.Object); ServerSubscribeFlow flow = new ServerSubscribeFlow(topicEvaluator.Object, sessionRepository.Object, retainedMessageRepository.Object, packetIdProvider, senderFlow.Object, configuration); await flow.ExecuteAsync(clientId, subscribe, channel.Object); senderFlow.Verify(f => f.SendPublishAsync(It.Is <string>(s => s == clientId), It.Is <Publish>(p => p.Topic == retainedTopic && p.QualityOfService == fooQoS && p.Payload.ToList().SequenceEqual(retainedPayload) && p.PacketId.HasValue && p.Retain), It.Is <IMqttChannel <IPacket> >(c => c == channel.Object), It.Is <PendingMessageStatus>(x => x == PendingMessageStatus.PendingToSend))); }
public async Task when_subscribing_new_topics_then_subscriptions_are_created_and_ack_is_sent() { MqttConfiguration configuration = new MqttConfiguration { MaximumQualityOfService = MqttQualityOfService.AtLeastOnce }; Mock <IMqttTopicEvaluator> topicEvaluator = new Mock <IMqttTopicEvaluator>(); Mock <IRepository <ClientSession> > sessionRepository = new Mock <IRepository <ClientSession> >(); IPacketIdProvider packetIdProvider = Mock.Of <IPacketIdProvider>(); IRepository <RetainedMessage> retainedMessageRepository = Mock.Of <IRepository <RetainedMessage> >(); IPublishSenderFlow senderFlow = Mock.Of <IPublishSenderFlow>(); string clientId = Guid.NewGuid().ToString(); ClientSession session = new ClientSession(clientId, clean: false); topicEvaluator.Setup(e => e.IsValidTopicFilter(It.IsAny <string>())).Returns(true); sessionRepository.Setup(r => r.Read(It.IsAny <string>())).Returns(session); MqttQualityOfService fooQoS = MqttQualityOfService.AtLeastOnce; string fooTopic = "test/foo/1"; Subscription fooSubscription = new Subscription(fooTopic, fooQoS); MqttQualityOfService barQoS = MqttQualityOfService.AtMostOnce; string barTopic = "test/bar/1"; Subscription barSubscription = new Subscription(barTopic, barQoS); ushort packetId = (ushort)new Random().Next(0, ushort.MaxValue); Subscribe subscribe = new Subscribe(packetId, fooSubscription, barSubscription); Mock <IMqttChannel <IPacket> > channel = new Mock <IMqttChannel <IPacket> >(); IPacket response = default; channel.Setup(c => c.SendAsync(It.IsAny <IPacket>())) .Callback <IPacket>(p => response = p) .Returns(Task.Delay(0)); Mock <IConnectionProvider> connectionProvider = new Mock <IConnectionProvider>(); connectionProvider .Setup(p => p.GetConnection(It.Is <string>(c => c == clientId))) .Returns(channel.Object); ServerSubscribeFlow flow = new ServerSubscribeFlow(topicEvaluator.Object, sessionRepository.Object, retainedMessageRepository, packetIdProvider, senderFlow, configuration); await flow.ExecuteAsync(clientId, subscribe, channel.Object); sessionRepository.Verify(r => r.Update(It.Is <ClientSession>(s => s.Id == clientId && s.Subscriptions.Count == 2 && s.Subscriptions.All(x => x.TopicFilter == fooTopic || x.TopicFilter == barTopic)))); Assert.NotNull(response); SubscribeAck subscribeAck = response as SubscribeAck; Assert.NotNull(subscribeAck); packetId.Should().Be(subscribeAck.PacketId); 2.Should().Be(subscribeAck.ReturnCodes.Count()); Assert.True(subscribeAck.ReturnCodes.Any(c => c == SubscribeReturnCode.MaximumQoS0)); Assert.True(subscribeAck.ReturnCodes.Any(c => c == SubscribeReturnCode.MaximumQoS1)); }
/// <summary> /// Sets properties and attributes of class in accordance with XML definition. /// </summary> /// <param name="Definition">XML definition</param> public override Task FromXml(XmlElement Definition) { this.actor = new StringAttribute(XML.Attribute(Definition, "actor")); this.topic = new StringAttribute(XML.Attribute(Definition, "topic")); this.qos = (MqttQualityOfService)XML.Attribute(Definition, "qos", MqttQualityOfService.AtMostOnce); this.retain = XML.Attribute(Definition, "retain", false); return(base.FromXml(Definition)); }
public MessageReceivedBookmark(string topic, string host, int port, string username, string password, MqttQualityOfService qos) { Topic = topic; Host = host; Port = port; Username = username; Password = password; Qos = qos; }
public MqttClientOptions(string topic, string host, int port, string username, string password, MqttQualityOfService qos) { Topic = topic; Host = host; Port = port; Username = username; Password = password; QualityOfService = qos; }
private async Task <ushort> PUBLISH(string Topic, MqttQualityOfService QoS, bool Retain, bool Duplicate, byte[] Data) { BinaryOutput Payload = new BinaryOutput(); ushort PacketIdentifier; Payload.WriteString(Topic); if (QoS > MqttQualityOfService.AtMostOnce) { PacketIdentifier = this.packetIdentifier++; if (PacketIdentifier == 0) { PacketIdentifier = this.packetIdentifier++; } Payload.WriteUInt16(PacketIdentifier); } else { PacketIdentifier = 0; } Payload.WriteBytes(Data); byte[] PayloadData = Payload.GetPacket(); BinaryOutput Packet = new BinaryOutput(); byte b = (byte)((int)MqttControlPacketType.PUBLISH << 4); if (Duplicate) { b |= 8; } b |= (byte)((int)QoS << 1); if (Retain) { b |= 1; } Packet.WriteByte(b); Packet.WriteUInt((uint)PayloadData.Length); Packet.WriteBytes(PayloadData); byte[] PacketData = Packet.GetPacket(); if (this.HasSniffers) { this.Information("PUBLISH(" + QoS.ToString() + ":" + Topic + ")"); } await this.Write(PacketData, PacketIdentifier, null); return(PacketIdentifier); }
public ConsumerWorkflow(IConfiguration configuration) { var section = configuration.GetSection("Mqtt"); _host = section.GetValue <string>("Host"); _port = section.GetValue <int>("Port"); _username = section.GetValue <string>("Username"); _password = section.GetValue <string>("Password"); _qos = section.GetValue <MqttQualityOfService>("QualityOfService"); }
private ushort PUBLISH(string Topic, MqttQualityOfService QoS, bool Retain, bool Duplicate, byte[] Data) { BinaryOutput Payload = new BinaryOutput(); ushort PacketIdentifier; Payload.WriteString(Topic); if (QoS > MqttQualityOfService.AtMostOnce) { PacketIdentifier = this.packetIdentifier++; if (PacketIdentifier == 0) { PacketIdentifier = this.packetIdentifier++; } Payload.WriteUInt16(PacketIdentifier); } else { PacketIdentifier = 0; } Payload.WriteBytes(Data); byte[] PayloadData = Payload.GetPacket(); BinaryOutput Packet = new BinaryOutput(); byte b = (byte)((int)MqttControlPacketType.PUBLISH << 4); if (Duplicate) { b |= 8; } b |= (byte)((int)QoS << 1); if (Retain) { b |= 1; } Packet.WriteByte(b); Packet.WriteUInt((uint)PayloadData.Length); Packet.WriteBytes(PayloadData); byte[] PacketData = Packet.GetPacket(); this.BeginWrite(PacketData, PacketIdentifier, null); return(PacketIdentifier); }
public void SetWill(string WillTopic, string WillData, bool WillRetain, MqttQualityOfService WillQoS) { if (this.willTopic != WillTopic || this.willData != WillData || this.willRetain != WillRetain || this.willQoS != WillQoS) { this.Close(); this.willTopic = WillTopic; this.willData = WillData; this.willRetain = WillRetain; this.willQoS = WillQoS; this.Open(); } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jObject = JObject.Load(reader); string topic = jObject["topic"].ToObject <string>(); MqttQualityOfService qos = jObject["qualityOfService"].ToObject <MqttQualityOfService>(); bool retain = jObject["retain"].ToObject <bool>(); string message = jObject["message"].ToObject <string>(); bool hasMessage = !string.IsNullOrEmpty((message)); byte[] payload = hasMessage ? Encoding.UTF8.GetBytes(message) : jObject["message"].ToObject <byte[]>(); return(new MqttLastWill(topic, qos, retain, payload)); }
async Task DispatchAsync(Publish publish, ClientSubscription subscription, bool isWill = false) { MqttQualityOfService requestedQos = isWill ? publish.QualityOfService : subscription.MaximumQualityOfService; MqttQualityOfService supportedQos = configuration.GetSupportedQos(requestedQos); bool retain = isWill ? publish.Retain : false; ushort? packetId = supportedQos == MqttQualityOfService.AtMostOnce ? null : (ushort?)_packetIdProvider.GetPacketId(); Publish subscriptionPublish = new Publish(publish.Topic, supportedQos, retain, duplicated: false, packetId: packetId) { Payload = publish.Payload }; IMqttChannel <IPacket> clientChannel = _connectionProvider.GetConnection(subscription.ClientId); await _senderFlow.SendPublishAsync(subscription.ClientId, subscriptionPublish, clientChannel); }
protected override Publish Read(byte[] bytes) { int remainingLength = MqttProtocol.Encoding.DecodeRemainingLength(bytes, out int remainingLengthBytesLength); byte packetFlags = bytes.Byte(0).Bits(5, 4); if (packetFlags.Bits(6, 2) == 0x03) { throw new MqttException(ClientProperties.Formatter_InvalidQualityOfService); } MqttQualityOfService qos = (MqttQualityOfService)packetFlags.Bits(6, 2); bool duplicated = packetFlags.IsSet(3); if (qos == MqttQualityOfService.AtMostOnce && duplicated) { throw new MqttException(ClientProperties.PublishFormatter_InvalidDuplicatedWithQoSZero); } bool retainFlag = packetFlags.IsSet(0); int topicStartIndex = 1 + remainingLengthBytesLength; string topic = bytes.GetString(topicStartIndex, out int nextIndex); if (!_topicEvaluator.IsValidTopicName(topic)) { throw new MqttException(ClientProperties.PublishFormatter_InvalidTopicName(topic)); } int variableHeaderLength = topic.Length + 2; ushort?packetId = default; if (qos != MqttQualityOfService.AtMostOnce) { packetId = bytes.Bytes(nextIndex, 2).ToUInt16(); variableHeaderLength += 2; } Publish publish = new Publish(topic, qos, retainFlag, duplicated, packetId); if (remainingLength > variableHeaderLength) { int payloadStartIndex = 1 + remainingLengthBytesLength + variableHeaderLength; publish.Payload = bytes.Bytes(payloadStartIndex); } return(publish); }
async Task SendQosAck(string clientId, MqttQualityOfService qos, Publish publish, IMqttChannel <IPacket> channel) { if (qos == MqttQualityOfService.AtMostOnce) { return; } else if (qos == MqttQualityOfService.AtLeastOnce) { await SendAckAsync(clientId, new PublishAck( publish.PacketId.Value ), channel); } else { await SendAckAsync(clientId, new PublishReceived( publish.PacketId.Value ), channel); } }
public async Task when_client_disconnects_by_protocol_then_will_message_is_not_sent() { using (IMqttClient client1 = await GetClientAsync()) using (IMqttClient client2 = await GetClientAsync()) using (IMqttClient client3 = await GetClientAsync()) { string topic = Guid.NewGuid().ToString(); MqttQualityOfService qos = MqttQualityOfService.ExactlyOnce; bool retain = true; FooWillMessage willMessage = new FooWillMessage { Message = "Client 1 has been disconnected unexpectedly" }; MqttLastWill will = new MqttLastWill(topic, qos, retain, willMessage.GetPayload()); await client1.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId()), will); await client2.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId())); await client3.ConnectAsync(new MqttClientCredentials( MqttTestHelper.GetClientId())); await client2.SubscribeAsync(topic, MqttQualityOfService.AtMostOnce); await client3.SubscribeAsync(topic, MqttQualityOfService.AtLeastOnce); ManualResetEventSlim willReceivedSignal = new ManualResetEventSlim(initialState: false); client2.MessageStream.Subscribe(m => { if (m.Topic == topic) { willReceivedSignal.Set(); } }); client3.MessageStream.Subscribe(m => { if (m.Topic == topic) { willReceivedSignal.Set(); } }); await client1.DisconnectAsync(); bool willReceived = willReceivedSignal.Wait(2000); Assert.False(willReceived); } }
public async Task when_unsubscribing_existing_subscriptions_then_subscriptions_are_deleted_and_ack_is_sent() { Mock <IRepository <ClientSession> > sessionRepository = new Mock <IRepository <ClientSession> >(); string clientId = Guid.NewGuid().ToString(); ushort packetId = (ushort)new Random().Next(0, ushort.MaxValue); string topic = "foo/bar/test"; MqttQualityOfService qos = MqttQualityOfService.AtLeastOnce; ClientSession session = new ClientSession(clientId, clean: false) { Subscriptions = new List <ClientSubscription> { new ClientSubscription { ClientId = clientId, MaximumQualityOfService = qos, TopicFilter = topic } } }; ClientSession updatedSession = default; sessionRepository.Setup(r => r.Read(It.IsAny <string>())).Returns(session); sessionRepository.Setup(r => r.Update(It.IsAny <ClientSession>())).Callback <ClientSession>(s => updatedSession = s); Unsubscribe unsubscribe = new Unsubscribe(packetId, topic); Mock <IMqttChannel <IPacket> > channel = new Mock <IMqttChannel <IPacket> >(); IPacket response = default; channel.Setup(c => c.SendAsync(It.IsAny <IPacket>())) .Callback <IPacket>(p => response = p) .Returns(Task.Delay(0)); Mock <IConnectionProvider> connectionProvider = new Mock <IConnectionProvider>(); connectionProvider .Setup(p => p.GetConnection(It.Is <string>(c => c == clientId))) .Returns(channel.Object); ServerUnsubscribeFlow flow = new ServerUnsubscribeFlow(sessionRepository.Object); await flow.ExecuteAsync(clientId, unsubscribe, channel.Object); Assert.NotNull(response); 0.Should().Be(updatedSession.Subscriptions.Count); UnsubscribeAck unsubscribeAck = response as UnsubscribeAck; Assert.NotNull(unsubscribeAck); packetId.Should().Be(unsubscribeAck.PacketId); }
public async void PublishAsync( string topic, byte[] payload, MqttQualityOfService qos = MqttQualityOfService.AtMostOnce) { var sessionState = await Client.ConnectAsync(Credentials); var message = new MqttApplicationMessage(topic, payload); await Client.PublishAsync(message, qos); await Client.DisconnectAsync(); // 若不中斷連接,此線不會結束。 return; }
public MqttBroker(MqttBrokerNode Node, string Host, int Port, bool Tls, string UserName, string Password, string WillTopic, string WillData, bool WillRetain, MqttQualityOfService WillQoS) { this.node = Node; this.host = Host; this.port = Port; this.tls = Tls; this.userName = UserName; this.password = Password; this.willTopic = WillTopic; this.willData = WillData; this.willRetain = WillRetain; this.willQoS = WillQoS; this.Open(); }
/// <summary> /// Publishes information on a topic. /// </summary> /// <param name="Topic">Topic name</param> /// <param name="QoS">Quality of service</param> /// <param name="Retain">If topic shoudl retain information.</param> /// <param name="Data">Binary data to send.</param> /// <returns>Packet identifier assigned to data.</returns> public int PUBLISH(string Topic, MqttQualityOfService QoS, bool Retain, byte[] Data) { return this.PUBLISH(Topic, QoS, Retain, false, Data); }
/// <summary> /// Publishes information on a topic. /// </summary> /// <param name="Topic">Topic name</param> /// <param name="QoS">Quality of service</param> /// <param name="Retain">If topic shoudl retain information.</param> /// <param name="Data">Binary data to send.</param> /// <returns>Packet identifier assigned to data.</returns> public int PUBLISH(string Topic, MqttQualityOfService QoS, bool Retain, BinaryOutput Data) { return this.PUBLISH(Topic, QoS, Retain, false, Data.GetPacket()); }
private ushort PUBLISH(string Topic, MqttQualityOfService QoS, bool Retain, bool Duplicate, byte[] Data) { BinaryOutput Payload = new BinaryOutput(); ushort PacketIdentifier; Payload.WriteString(Topic); if (QoS > MqttQualityOfService.AtMostOne) { PacketIdentifier = this.packetIdentifier++; if (PacketIdentifier == 0) PacketIdentifier = this.packetIdentifier++; Payload.WriteUInt16(PacketIdentifier); } else PacketIdentifier = 0; Payload.WriteBytes(Data); byte[] PayloadData = Payload.GetPacket(); BinaryOutput Packet = new BinaryOutput(); byte b = (byte)((int)MqttControlPacketType.PUBLISH << 4); if (Duplicate) b |= 8; b |= (byte)((int)QoS << 1); if (Retain) b |= 1; Packet.WriteByte(b); Packet.WriteUInt((uint)PayloadData.Length); Packet.WriteBytes(PayloadData); byte[] PacketData = Packet.GetPacket(); this.BeginWrite(PacketData, PacketIdentifier); return PacketIdentifier; }