示例#1
0
        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;
            }
        }
示例#2
0
        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;
            }
        }
示例#3
0
        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);
        }
示例#4
0
        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);
        }
示例#5
0
        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));
        }
示例#6
0
 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);
 }
示例#7
0
        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);
                }
            }
        }
示例#8
0
 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);
         }
     }
 }
示例#9
0
 public Task CloseSession(IMqttSession session)
 {
     //TODO: Clean up subscriptions if cleansession
     return(Util.CompletedTask);
 }
示例#10
0
 public MqttClient(IMqttStorageProvider storageProvider, IMqttSession session)
 {
     this.storageProvider = storageProvider;
     this.session         = session;
 }
示例#11
0
        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);
        }
示例#12
0
 Task IMqttSessionProvider.CloseSession(IMqttSession session)
 {
     //TODO: Clean up subscriptions if cleansession
     return(Util.CompletedTask);
 }