Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        public string ReadString()
        {
            int length = ReadLength();

            // No need to read any data for an empty string.
            if (length == 0)
            {
                return("");
            }

            CheckReadSize(length);

            // Fast path:  We already have the bytes in a contiguous buffer, so
            //   just copy directly from it.
            String result = Utf8Encoding.GetString(mBuffer, mReadPos, length);

            mReadPos += length;
            return(result);
        }
Ejemplo n.º 3
0
        /// <summary>
        ///  _register the pure consumers
        /// </summary>
        /// <param name="messageProcessor">An class object which contains attributed methods to register</param>
        private void _registerConsumers <T>(T messageProcessor) where T : class =>
        // First we need to select the methods that are attributed with the Consume attribute.
        messageProcessor.GetType()
        .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
        .Where(method => method.IsDefined(typeof(Consume)))
        .Where(method => !method.IsDefined(typeof(ConsumeAndRespond)))
        .Where(method => method.ReturnType == typeof(void))
        .Where(method => method.GetParameters().Length == 1)
        .Where(method => method.GetParameters()[0].ParameterType.IsClass)
        .ForEach(method =>
        {
            // Get the attribute
            var attribute = method.GetCustomAttribute <Consume>();

            // Create a unique identifier. It makes sure, that tow methods with the same name from different
            // commandProcessors do not override each other.
            var uniqueIdentifier = messageProcessor.GetType().FullName + _buildIdentifier(method);

            // Should the topic contain mqtt wildcards, replace them with regex wildcards
            var topic = _containsWildcards(attribute.Topic)
                            ? _replaceWildCards(attribute.Topic)
                            : attribute.Topic;

            // Get the existing list of consumers for that topic OR create a new one, if none existed.
            if (!_consumers.Keys.Any(key => Regex.IsMatch(key, topic)))
            {
                _consumers[topic] = new Dictionary <string, Action <byte[]> >();
            }

            // Add an IdentifiableAction to the list of consumers. It takes its identifier and the payload
            // of the message that arrived.
            _consumers[topic][uniqueIdentifier] =
                bytes =>
            {
                // Get the type of the parameter of the method about to be invoked
                var type = method.GetParameters()[0].ParameterType;

                // Deserialize
                object message;
                try
                {
                    var jsonString = Utf8Encoding.GetString(bytes);
                    message        = JsonConvert.DeserializeObject(jsonString, type);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    Console.WriteLine(
                        $"{nameof(JsonConvert.DeserializeObject)} failed for type {type.FullName}");
                    throw;
                }

                try
                {
                    method.Invoke(messageProcessor, new[] { message });
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    Console.WriteLine(
                        $"Invoking method {method.Name} failed with parameter {type.FullName}");
                    throw;
                }

                // Should the logger string be set...
                if (!string.IsNullOrWhiteSpace(attribute.Logger))
                {
                    // ..send the received message to the message logger
                    _bus.PublishAsync(
                        new MqttApplicationMessage(attribute.Logger, bytes), attribute.LoggerQoS);
                }
            };
        }
                 );