internal async Task PublishReceived(IMqttSession session, Stream stream, PublishMessage publishMessage) { await publishMessage.ReadPayloadAsync(); //If we've already received the QoS 2 message and forwarded it, then just send the PubRec if (publishMessage.QoS == QoS.AtMostOnce && await session.HasQoS2(publishMessage.PacketId.Value)) { await new PubRecMessage(publishMessage.PacketId.Value).Write(stream); return; } if (publishMessage.Retain) { await storageProvider.PutRetained(publishMessage.Topic, publishMessage.Payload); } await PublishMessage(await sessionProvider.GetSubscriptions(publishMessage.Topic), publishMessage.Topic, publishMessage.Payload); switch (publishMessage.QoS) { case QoS.AtLeastOnce: await new PubAckMessage(publishMessage.PacketId.Value).Write(stream); break; case QoS.AtMostOnce: await session.StoreQoS2(publishMessage.PacketId.Value); await new PubRecMessage(publishMessage.PacketId.Value).Write(stream); break; case QoS.BestEffort: default: break; } }
internal void PublishReceived(IMqttSession session, MqttPublishMessage publishMessage) { if (publishMessage.Header.Qos == MqttQos.BestEffort && session.HasQoS2(publishMessage.VariableHeader.MessageIdentifier)) { var pubRec = new MqttPublishReceivedMessage() .WithMessageIdentifier(publishMessage.VariableHeader.MessageIdentifier); session.Write(pubRec); } if (publishMessage.Header.Retain) { this.storageProvider.PutRetained(publishMessage.VariableHeader.TopicName, publishMessage.Payload.Message.ToArray()); } PublishMessage(GetSubscriptions(publishMessage.VariableHeader.TopicName), publishMessage.VariableHeader.TopicName, publishMessage.Payload.Message.ToArray()); switch (publishMessage.Header.Qos) { case MqttQos.AtLeastOnce: var puback = new MqttPublishAckMessage().WithMessageIdentifier(publishMessage.VariableHeader.MessageIdentifier); session.Write(puback); break; case MqttQos.AtMostOnce: session.StoreQoS2(publishMessage.VariableHeader.MessageIdentifier); var pubRec = new MqttPublishReleaseMessage().WithMessageIdentifier(publishMessage.VariableHeader.MessageIdentifier); session.Write(pubRec); break; case MqttQos.BestEffort: default: break; } }
private void SubscribeReceived(IMqttSession session, MqttSubscribeMessage subscribeMessage) { MqttSubscribeAckMessage subAck = new MqttSubscribeAckMessage().WithMessageIdentifier(subscribeMessage.VariableHeader.MessageIdentifier); AddSubscriptions(session, subscribeMessage.Payload.Subscriptions); session.Write(subAck); PublishMessages(session, storageProvider.GetRetained(subscribeMessage.Payload.Subscriptions), true); }
private async Task SubscribeReceived(IMqttSession session, NetworkStream stream, SubscribeMessage subscribeMessage) { //TODO: Deal with subscriptions that are denied. SubAckMessage subAck = new SubAckMessage(subscribeMessage.PacketId, await sessionProvider.AddSubscriptions(session, subscribeMessage.Subscriptions)); await subAck.Write(stream); await PublishMessages(session, stream, await storageProvider.GetRetained(subscribeMessage.Subscriptions), true); }
public Task <IReadOnlyCollection <MqttQos> > AddSubscriptions(IMqttSession session, IReadOnlyDictionary <string, MqttQos> subscriptions) { List <MqttQos> result = new List <MqttQos>(); foreach (KeyValuePair <string, MqttQos> subscription in subscriptions) { SubscriptionNode node = LookupNode(subscription.Key); if (node.subscribers == null) { node.subscribers = new Dictionary <IMqttSession, MqttQos>(); } node.subscribers[session] = subscription.Value; result.Add(subscription.Value); } return(Util.RunSynchronously <IReadOnlyCollection <MqttQos> >(() => result)); }
public Task RemoveSubscriptions(IMqttSession session, IEnumerable <string> topicFilters) { foreach (string topicFilter in topicFilters) { SubscriptionNode node = LookupNode(topicFilter); if (node.subscribers != null && node.subscribers.Remove(session)) { //TODO: clean up dead branches, recursively. // if (node.subscribers.Count == 0 && node.children.Count == 0) // { // int lastSlash = topicFilter.LastIndexOf('/') // string parentTopic = topicFilter.Substring(0, topicFilter.LastIndexOf('/')); // SubscriptionNode parentNode = LookupNode(parentTopic); // parentNode.children.Remove() // } } } return(Util.CompletedTask); }
private async Task PublishMessages(IMqttSession session, Stream stream, IEnumerable <Tuple <string, QoS, byte[]> > messages, bool retained) { foreach (var message in messages) { string messageId = null; short? packetId = null; //QOS 1 or 2, store in storage, and in session. if (message.Item2 != QoS.BestEffort) { messageId = await storageProvider.StoreMessage(new InFlightMessage(message.Item1, message.Item3)); session.Publish(messageId, message.Item2); } else { //QoS 0 just publish, that way the session can keep a straight up queue and not block QoS 0 messages from //intervening. PublishMessage publishMessage = new PublishMessage(false, retained, message.Item2, message.Item1, message.Item3, packetId); await publishMessage.Write(stream); } } }
private void PublishMessages(IMqttSession session, IEnumerable <Tuple <string, MqttQos, byte[]> > messages, bool retained) { foreach (var message in messages) { string messageId = null; short? packetId = null; //QOS 1 or 2, store in storage, and in session. if (message.Item2 != MqttQos.BestEffort) { messageId = storageProvider.StoreMessage(new InFlightMessage(message.Item1, message.Item3)); session.Publish(messageId, message.Item2); } else { //QoS 0 just publish, that way the session can keep a straight up queue and not block QoS 0 messages from //intervening. MqttPublishMessage publishMessage = new MqttPublishMessage().WithQos(message.Item2).ToTopic(message.Item1).PublishData(message.Item3); publishMessage.Header.Retain = retained; publishMessage.Header.Duplicate = false; session.Write(publishMessage); } } }
public Task CloseSession(IMqttSession session) { //TODO: Clean up subscriptions if cleansession return(Util.CompletedTask); }
public MqttClient(IMqttStorageProvider storageProvider, IMqttSession session) { this.storageProvider = storageProvider; this.session = session; }
private async void handleConnection(TcpClient connection) { var ep = connection.Client.RemoteEndPoint; Console.WriteLine("New Connection from {0}", ep); NetworkStream stream = connection.GetStream(); MqttMessage message = await MqttMessage.Read(stream, 5); if (message.Type != MessageType.Connect) { throw new MqttProtocolException("First packet not connect"); } //TODO: Non-clean sessions ConnAckMessage connAck = new ConnAckMessage(0, false); await connAck.Write(stream); ConnectMessage connectMessage = (ConnectMessage)message; double keepalive = ((ConnectMessage)message).KeepAlive * 1.5; String clientId = ((ConnectMessage)message).ClientId; if (String.IsNullOrEmpty(clientId)) { clientId = Guid.NewGuid().ToString(); } IMqttSession session = await sessionProvider.NewSession(clientId); Console.WriteLine("Client {0} connected from {1} ({2},{3})", clientId, ep, connectMessage.CleanSession, connectMessage.KeepAlive); connections.Add(session, connection); Task <MqttMessage> incoming = MqttMessage.Read(stream); Task <PendingMessage> outgoing = session.NextPending(null, 0); while (connection.Connected) { try { if (await Task.WhenAny(incoming, outgoing) == incoming) { try { message = incoming.Result; } catch (AggregateException e) { Console.WriteLine(e.InnerException.Message); connections.Remove(session); connection.Close(); continue; } catch (Exception e) { Console.WriteLine(e.Message); connections.Remove(session); connection.Close(); continue; } switch (message.Type) { case MessageType.Publish: await PublishReceived(session, stream, (PublishMessage)message); break; case MessageType.Disconnect: Console.WriteLine("Client {0} disconnected cleanly", clientId); connections.Remove(session); connection.Close(); //Skip reading the next message. Loop should exit. continue; case MessageType.Subscribe: await SubscribeReceived(session, stream, (SubscribeMessage)message); break; case MessageType.Unsubscribe: await sessionProvider.RemoveSubscriptions(session, ((UnsubscribeMessage)message).TopicFilters); await new UnsubAckMessage(((UnsubscribeMessage)message).PacketId).Write(stream); break; case MessageType.PubAck: string messageId = await session.PublishAcknowledged(((PubAckMessage)message).PacketId); if (messageId != null) { await storageProvider.ReleaseMessage(messageId); } break; case MessageType.PubRec: messageId = await session.PublishReceived(((PubRecMessage)message).PacketId); if (messageId != null) { await storageProvider.ReleaseMessage(messageId); } break; case MessageType.PubRel: await session.RemoveQoS2(((PubRelMessage)message).PacketId); await new PubCompMessage(((PubRelMessage)message).PacketId).Write(stream); break; case MessageType.PubComp: await session.PublishCompleted(((PubCompMessage)message).PacketId); break; case MessageType.PingReq: await new PingRespMessage().Write(stream); break; } incoming = MqttMessage.Read(stream); } else { PendingMessage pendingMessage = outgoing.Result; PendingPublishMessage pendingPublish = pendingMessage as PendingPublishMessage; if (pendingPublish != null) { var messageInfo = await storageProvider.GetMessage(pendingPublish.MessageId); message = new PublishMessage(pendingPublish.Duplicate, false, pendingPublish.QoS, messageInfo.Topic, messageInfo.Payload, pendingPublish.PacketId); } else { message = new PubRelMessage(pendingMessage.PacketId); } await message.Write(stream); outgoing = session.NextPending(pendingMessage, 5000); } } catch (Exception e) { Console.Out.WriteLine(e.Message); } } await sessionProvider.CloseSession(session); }
Task IMqttSessionProvider.CloseSession(IMqttSession session) { //TODO: Clean up subscriptions if cleansession return(Util.CompletedTask); }