/// <summary> /// Sets the Qos level of the last topic added to the subscription list via a call to ToTopic(string) /// </summary> /// <param name="qos">The Qos to set the last topic subscription to.</param> /// <returns>An update instance of the message.</returns> public MqttSubscribeMessage AtQos(MqttQos qos) { if (this.Payload.Subscriptions.ContainsKey(lastTopic)) { this.Payload.Subscriptions[lastTopic] = qos; } return this; }
public static short Publish(string topic, MqttQos qos, byte[] data) { if (mqttClient == null) { throw new InvalidOperationException("You must call Connect() on the MqttClientManager before attempting to publish"); } return mqttClient.PublishMessage(topic, qos, data); }
public void SubscriptionRequestCreatesPendingSubscription() { var chMock = new Mock <IMqttConnectionHandler>(); var pubMock = new Mock <IPublishingManager>(); const string topic = "testtopic"; const MqttQos qos = MqttQos.AtMostOnce; // run and verify the mocks were called. var subs = new Nmqtt.SubscriptionsManager(chMock.Object, pubMock.Object); subs.RegisterSubscription <string, AsciiPayloadConverter>(topic, qos); Assert.Equal(SubscriptionStatus.Pending, subs.GetSubscriptionsStatus(topic)); }
/// <summary> /// 发布消息 /// </summary> /// <param name="topic">主题</param> /// <param name="payload">有效载荷</param> /// <param name="qos">服务质量等级</param> public Task PublishAsync(string topic, byte[] payload, MqttQos qos = MqttQos.AtMostOnce) { var packet = new PublishPacket(qos) { TopicName = topic, Payload = payload }; if (qos > MqttQos.AtMostOnce) { packet.PacketId = _packetIdentifierProvider.GetNewPacketId(); } return(_clientChannel.WriteAndFlushAsync(packet)); }
/// <summary> /// 发布消息 /// </summary> /// <param name="topic">主题</param> /// <param name="payload">有效载荷</param> /// <param name="qos">服务质量等级</param> /// <param name="retain"></param> public Task PublishAsync(string topic, byte[] payload, MqttQos qos = MqttQos.AtMostOnce, bool retain = false, CancellationToken cancellationToken = default) { var packet = new PublishPacket(qos, false, retain) { TopicName = topic, Payload = payload }; if (qos > MqttQos.AtMostOnce) { packet.PacketId = _packetIdProvider.NewPacketId(); } return(SendAndFlushPacketAsync(packet)); }
void AddRetainedRecursive(string topic, RetainedNode node, MqttQos qos, List <Tuple <string, MqttQos, byte[]> > result) { if (node.children == null) { return; } foreach (var child in node.children) { string childTopic = topic + "/" + child.Key; if (child.Value.body != null) { result.Add(new Tuple <string, MqttQos, byte[]>(childTopic, qos, child.Value.body)); } AddRetainedRecursive(childTopic, child.Value, qos, result); } }
/// <summary> /// Creates a payload from the specified header stream. /// </summary> /// <param name="payloadStream"></param> public override void ReadFrom(Stream payloadStream) { int payloadBytesRead = 0; int payloadLength = header.MessageSize - variableHeader.Length; // read all the topics and qos subscriptions from the message payload while (payloadBytesRead < payloadLength) { string topic = payloadStream.ReadMqttString(); MqttQos qos = (MqttQos)payloadStream.ReadByte(); payloadBytesRead += topic.Length + 3; // +3 = Mqtt string length bytes + qos byte AddSubscription(topic, qos); } }
public void MultipleSubscriptionsForSamePendingThrowsException() { var chMock = new Mock <IMqttConnectionHandler>(); // mock the call to register and save the callback for later. chMock.Setup((x) => x.RegisterForMessage(MqttMessageType.SubscribeAck, It.IsAny <Func <MqttMessage, bool> >())); string topic = "testtopic"; MqttQos qos = MqttQos.AtMostOnce; // run and verify the mocks were called. Nmqtt.SubscriptionsManager subs = new Nmqtt.SubscriptionsManager(chMock.Object); subs.RegisterSubscription <AsciiPublishDataConverter>(topic, qos); chMock.VerifyAll(); Assert.Throws <ArgumentException>(() => subs.RegisterSubscription <AsciiPublishDataConverter>(topic, qos)); }
public static void Subscribe(string topic, MqttQos qos, Func<string, object, bool> callback) { if (mqttClient == null) { throw new InvalidOperationException("You must call Connect() on the MqttClientManager before attempting to subscribe"); } // if we don't have any for this topic yet, subscribe with the topic. if (subscriptions.Count(x => x.Topic == topic) == 0) { mqttClient.Subscribe(topic, qos, MessageReceiver); } // add it to the subscriptions list PublishSubscription pSub = new PublishSubscription(topic, callback); subscriptions.Add(pSub); }
static void DecodeSubAckPayload(IByteBuffer buffer, SubAckPacket packet, ref int remainingLength) { var returnCodes = new MqttQos[remainingLength]; for (int i = 0; i < remainingLength; i++) { var returnCode = (MqttQos)buffer.ReadByte(); if (returnCode > MqttQos.ExactlyOnce && returnCode != MqttQos.Failure) { throw new DecoderException($"[MQTT-3.9.3-2]. Invalid return code: {returnCode}"); } returnCodes[i] = returnCode; } packet.ReturnCodes = returnCodes; remainingLength = 0; }
public override void Decode(IByteBuffer buffer) { base.Decode(buffer); var returnCodes = new MqttQos[RemaingLength]; for (int i = 0; i < RemaingLength; i++) { var returnCode = (MqttQos)buffer.ReadByte(); if (returnCode > MqttQos.ExactlyOnce && returnCode != MqttQos.Failure) { throw new DecoderException($"[MQTT-3.9.3-2]. Invalid return code: {returnCode}"); } returnCodes[i] = returnCode; } ReturnCodes = returnCodes; FixedHeader.RemaingLength = 0; }
public ushort Publish(string topic, byte[] message, MqttQos qos = MqttQos.AtMostOnce, bool retained = false) { if (IsDisposed) { throw new ObjectDisposedException("MqttConnection"); } else if (!IsConnected) { throw new InvalidOperationException("Not connected"); } return(Publish(new PublishPacket() { Topic = topic, Message = message, QosLevel = qos, Retain = retained })); }
public void GetSubscriptionWithValidTopicReturnsSubscription() { Func <MqttMessage, bool> theCallback = null; var chMock = new Mock <IMqttConnectionHandler>(); chMock.Setup((x) => x.RegisterForMessage(MqttMessageType.SubscribeAck, It.IsAny <Func <MqttMessage, bool> >())) .Callback((MqttMessageType msgtype, Func <MqttMessage, bool> cb) => theCallback = cb); string topic = "testtopic"; MqttQos qos = MqttQos.AtMostOnce; // run and verify the mocks were called. Nmqtt.SubscriptionsManager subs = new Nmqtt.SubscriptionsManager(chMock.Object); var subid = subs.RegisterSubscription <AsciiPublishDataConverter>(topic, qos); // execute the callback that would normally be initiated by the connection handler when a sub ack message arrived. theCallback(new MqttSubscribeAckMessage().WithMessageIdentifier(subid).AddQosGrant(MqttQos.AtMostOnce)); Assert.NotNull(subs.GetSubscription(topic)); }
/// <summary> /// Registers a new subscription with the subscription manager. /// </summary> /// <param name="topic"></param> /// <param name="qos"></param> /// <returns>The subscription message identifier.</returns> internal short RegisterSubscription <TPublishDataConverter>(string topic, MqttQos qos) where TPublishDataConverter : IPublishDataConverter { // check we don't have a pending subscription request for the topic. var pendingSubs = from ps in pendingSubscriptions.Values where ps.Topic.Equals(topic) select ps; if (pendingSubs.Count <Subscription>() > 0) { throw new ArgumentException("There is already a pending subscription for this topic"); } // no pending subscription, if we already have a subscription then throw it back out as well if (subscriptions.ContainsKey(topic)) { // TODO: we might want to treat this as an ignore/silent confirm because they will be receiving messages for the topic already throw new ArgumentException("You are already subscribed for this topic"); } // Add a pending subscription... Subscription sub = new Subscription() { Topic = topic, Qos = qos, MessageIdentifier = MessageIdentifierDispenser.GetNextMessageIdentifier("subscriptions"), CreatedTime = DateTime.Now, DataProcessor = Activator.CreateInstance <TPublishDataConverter>() }; pendingSubscriptions.Add(sub.MessageIdentifier, sub); // build a subscribe message for the caller. MqttSubscribeMessage msg = new MqttSubscribeMessage() .WithMessageIdentifier(sub.MessageIdentifier) .ToTopic(sub.Topic) .AtQos(sub.Qos); connectionHandler.SendMessage(msg); return(msg.VariableHeader.MessageIdentifier); }
/// <summary> /// Publish a message to the broker on the specified topic. /// </summary> /// <param name="topic">The topic to send the message to.</param> /// <param name="qualityOfService">The QOS to use when publishing the message.</param> /// <param name="data">The message to send.</param> /// <returns>The message identifier assigned to the message.</returns> public short Publish<T, TPayloadConverter>(string topic, MqttQos qualityOfService, T data) where TPayloadConverter : IPayloadConverter<T>, new() { var msgId = messageIdentifierDispenser.GetNextMessageIdentifier(String.Format("Topic:{0}", topic)); Log.DebugFormat("Publishing message ID {0} on topic {1} using QOS {2}", msgId, topic, qualityOfService); var converter = GetPayloadConverter<TPayloadConverter>(); var msg = new MqttPublishMessage() .ToTopic(topic) .WithMessageIdentifier(msgId) .WithQos(qualityOfService) .PublishData(converter.ConvertToBytes(data)); // QOS level 1 or 2 messages need to be saved so we can do the ack processes if (qualityOfService == MqttQos.AtLeastOnce || qualityOfService == MqttQos.ExactlyOnce) { publishedMessages.Add(msgId, msg); } connectionHandler.SendMessage(msg); return msgId; }
void IMqttSession.Publish(string messageId, MqttQos qos) { var publish = new PendingPublishMessage(1, messageId, qos); //WARNING: Something you may not expect //SetResult will transfer control to a waiter if there is one. We need to get our queue straight before that happens //Or else whack shit goes wrong. So don't go thinking "it's prettier to see if the queue is empty before queueing". //Not that this was ever coded that way or anything... pendingMessages.Enqueue(publish); //If this is the first message, signal. if (pendingMessages.Count == 1 && pendingMessageCompletionSource != null) { TaskCompletionSource <PendingMessage> source = pendingMessageCompletionSource; pendingMessageCompletionSource = null; source.SetResult(publish); } if (qos == MqttQos.BestEffort) { pendingMessages.Enqueue(new PendingPubRelMessage(1)); } }
/// <summary> /// Publish a message to the broker on the specified topic. /// </summary> /// <param name="topic">The topic to send the message to.</param> /// <param name="payload">The message to send.</param> /// <returns>The message identifier assigned to the message.</returns> public short Publish <TDataConverter>(string topic, MqttQos qualityOfService, object data) where TDataConverter : IPublishDataConverter { short msgID = MessageIdentifierDispenser.GetNextMessageIdentifier(String.Format("Topic:{0}", topic)); IPublishDataConverter converter = GetPublishDataConverter <TDataConverter>(); MqttPublishMessage msg = new MqttPublishMessage() .ToTopic(topic) .WithMessageIdentifier(msgID) .WithQos(qualityOfService) .PublishData(converter.ConvertToBytes(data)); // QOS level 1 or 2 messages need to be saved so we can do the ack processes if (qualityOfService == MqttQos.AtLeastOnce || qualityOfService == MqttQos.ExactlyOnce) { publishedMessages.Add(msgID, msg); } connectionHandler.SendMessage(msg); return(msgID); }
public void SubscriptionRequestInvokesSend() { MqttSubscribeMessage subMsg = null; var chMock = new Mock <IMqttConnectionHandler>(); // mock the call to register and save the callback for later. chMock.Setup((x) => x.RegisterForMessage(MqttMessageType.SubscribeAck, It.IsAny <Func <MqttMessage, bool> >())); // mock the call to Send(), which should occur when the subscription manager tries to subscribe chMock.Setup(x => x.SendMessage(It.IsAny <MqttSubscribeMessage>())) .Callback((MqttMessage msg) => subMsg = (MqttSubscribeMessage)msg); string topic = "testtopic"; MqttQos qos = MqttQos.AtMostOnce; // run and verify the mocks were called. Nmqtt.SubscriptionsManager subs = new Nmqtt.SubscriptionsManager(chMock.Object); subs.RegisterSubscription <AsciiPublishDataConverter>(topic, qos); chMock.VerifyAll(); // now check the message generated by the subscription manager was good - ie contain the topic at the specified qos Assert.Contains(topic, subMsg.Payload.Subscriptions.Keys); Assert.Equal <MqttQos>(MqttQos.AtMostOnce, subMsg.Payload.Subscriptions[topic]); }
/// <summary> /// Sets the Qos of the message header. /// </summary> /// <param name="qos">The Qos to ser</param> /// <returns>An instance of the header.</returns> public MqttHeader WithQos(MqttQos qos) { this.Qos = qos; return(this); }
/// <summary> /// Publishes a message to the message broker. /// </summary> /// <param name="topic">The topic to publish the message to.</param> /// <param name="qos">The QOS level to publish the message at.</param> /// <param name="data">The message to publish.</param> /// <returns>The message identiier assigned to the message.</returns> public short PublishMessage(string topic, MqttQos qos, byte[] data) { return(PublishMessage <byte[], PassThroughPayloadConverter>(topic, qos, data)); }
public IObservable <MqttReceivedMessage <T> > ListenTo <T, TPayloadConverter>(string topic, MqttQos qosLevel) where TPayloadConverter : IPayloadConverter <T>, new() { if (connectionHandler.State != ConnectionState.Connected) { throw new ConnectionException(connectionHandler.State); } return(subscriptionsManager.RegisterSubscription <T, TPayloadConverter>(topic, qosLevel)); }
/// <summary> /// Subscribles the specified topic with a callback function that accepts the raw message data. /// </summary> /// <param name="topic">The topic.</param> /// <param name="qosLevel">The qos level.</param> /// <returns></returns> /// <exception cref="InvalidTopicException">If a topic that does not meet the MQTT topic spec rules is provided.</exception> public IObservable <MqttReceivedMessage <byte[]> > ListenTo(string topic, MqttQos qosLevel) { return(ListenTo <byte[], PassThroughPayloadConverter>(topic, qosLevel)); }
/// <summary> /// Sets the WillQos of the connect flag. /// </summary> /// <param name="qos">The qos.</param> /// <returns></returns> public MqttConnectMessage WithWillQos(MqttQos qos) { this.VariableHeader.ConnectFlags.WillQos = qos; return this; }
/// <summary> /// Adds a subscription grant to the message. /// </summary> /// <param name="qosGranted">The granted Qos to add.</param> /// <returns>The updated instance of the message.</returns> public MqttSubscribeAckMessage AddQosGrant(MqttQos qosGranted) { this.Payload.AddGrant(qosGranted); return this; }
/// <summary> /// Sets the Qos of the published message. /// </summary> /// <param name="qos">The qos to set.</param> /// <returns>The updated instance of the message.</returns> public MqttPublishMessage WithQos(MqttQos qos) { this.Header.WithQos(qos); return this; }
public void Subscribe(string topic, MqttQos qosLevel) { Subscribe(new string[] { topic }, new MqttQos[] { qosLevel }); }
/// <summary> /// Adds a new subscription to the collection of subscriptions. /// </summary> /// <param name="grantedQos">The granted qos.</param> public void AddGrant(MqttQos grantedQos) { qosGrants.Add(grantedQos); }
public MqttSubscriberConstrains(string subsciberId, MqttQos qos) { this.SubsciberId = subsciberId; this.Qos = qos; }
/// <summary> /// Adds a subscription grant to the message. /// </summary> /// <param name="qosGranted">The granted Qos to add.</param> /// <returns>The updated instance of the message.</returns> public MqttSubscribeAckMessage AddQosGrant(MqttQos qosGranted) { this.Payload.AddGrant(qosGranted); return(this); }
public MqttClient(NumbersPersistence numbersPersistence, IMqttPersistence clientPersistence, string topicRoot, string clientId, MqttQos qos, int maxNumber) { this.clientPersistence = clientPersistence; this.numbersPersistence = numbersPersistence; ClientId = clientId; TopicToPublish = topicRoot + "/" + clientId; TopicToSubscribe = topicRoot + "/#"; Qos = qos; this.maxNumber = maxNumber; this.previousPublishedNumber = numbersPersistence.GetLastNumberSent(); }
/// <summary> /// Sets the Qos of the message header. /// </summary> /// <param name="qos">The Qos to ser</param> /// <returns>An instance of the header.</returns> public MqttHeader WithQos(MqttQos qos) { this.Qos = qos; return this; }
/// <summary> /// Creates a new subscription for the specified topic. /// </summary> /// <typeparam name="T">The type of data the subscription is expected to return.</typeparam> /// <typeparam name="TPayloadConverter">The type of the converter that can convert from bytes to the type T.</typeparam> /// <param name="topic">The topic to subscribe to.</param> /// <param name="qos">The QOS level to subscribe at.</param> /// <returns>An observable that yields messages when they arrive.</returns> /// <exception cref="InvalidTopicException">If a topic that does not meet the MQTT topic spec rules is provided.</exception> private IObservable <MqttReceivedMessage <T> > CreateNewSubscription <T, TPayloadConverter>(string topic, MqttQos qos) where TPayloadConverter : IPayloadConverter <T>, new() { Log.Info(m => m("Creating subscription for topoc {0} @ QOS {1}.", topic, qos)); try { var subscriptionTopic = new SubscriptionTopic(topic); // Get an ID that represents the subscription. We will use this same ID for unsubscribe as well. var msgId = messageIdentifierDispenser.GetNextMessageIdentifier("subscriptions"); // create a new observable that is used to yield messages // that arrive for the topoc. var observable = CreateObservableForSubscription(subscriptionTopic, msgId); var sub = new Subscription { Topic = subscriptionTopic, Qos = qos, MessageIdentifier = msgId, CreatedTime = DateTime.Now, Observable = observable, }; pendingSubscriptions.Add(sub.MessageIdentifier, sub); // build a subscribe message for the caller and send it off to the broker. var msg = new MqttSubscribeMessage().WithMessageIdentifier(sub.MessageIdentifier) .ToTopic(sub.Topic.ToString()) .AtQos(sub.Qos); connectionHandler.SendMessage(msg); return(WrapSubscriptionObservable <T, TPayloadConverter>(sub.Observable)); } catch (ArgumentException ex) { Log.Warn(m => m("Error while processing topoc {0}. topoc structure not valid.", topic), ex); throw new InvalidTopicException(ex.Message, topic, ex); } }
/// <summary> /// 订阅主题 /// </summary> /// <param name="topic">主题</param> /// <param name="qos">服务质量等级</param> public void Add(string topic, MqttQos qos) { _subscribeTopics.Add(new SubscriptionRequest(topic, qos)); }
/// <summary> /// Registers a new subscription with the subscription manager. /// </summary> /// <param name="topic"></param> /// <param name="qos"></param> /// <returns>An IObservable that yields any messages received once subscribed.</returns> /// <exception cref="InvalidTopicException">If a topic that does not meet the MQTT topic spec rules is provided.</exception> public IObservable <MqttReceivedMessage <T> > RegisterSubscription <T, TPayloadConverter>(string topic, MqttQos qos) where TPayloadConverter : IPayloadConverter <T>, new() { // if we have a pending subscription or established subscription just return the existing observable. lock (subscriptionPadlock) { IObservable <MqttReceivedMessage <T> > existingObservable; if (TryGetExistingSubscription <T, TPayloadConverter>(topic, out existingObservable)) { return(existingObservable); } return(CreateNewSubscription <T, TPayloadConverter>(topic, qos)); } }
public SubscriptionRequest(string topic, MqttQos qos) { Topic = topic; Qos = qos; }
/// <summary> /// Adds a new subscription to the collection of subscriptions. /// </summary> /// <param name="topic">The topic to subscribe to.</param> /// <param name="qos">The qos level to subscribe at.</param> public void AddSubscription(string topic, MqttQos qos) { if (Subscriptions.ContainsKey(topic)) { Subscriptions[topic] = qos; } else { Subscriptions.Add(topic, qos); } }
/// <summary> /// Sets the WillQos of the connect flag. /// </summary> /// <param name="qos">The qos.</param> /// <returns></returns> public MqttConnectMessage WithWillQos(MqttQos qos) { this.VariableHeader.ConnectFlags.WillQos = qos; return(this); }
/// <summary> /// Writes the fixed header with the specified qos level and flags zeroed. /// </summary> /// <param name="packetType">Packet type.</param> /// <param name="qosLevel">Qos level.</param> internal void SetFixedHeader(byte packetType, MqttQos qosLevel) { fixedHeader = (byte)(packetType << Packet.PacketTypeOffset); fixedHeader |= (byte)((byte)qosLevel << Packet.QosLevelOffset); }