генерирование обратных вызовов mqtt изнутри класса с использованием декоратора - PullRequest
0 голосов
/ 28 сентября 2019

Чтобы упростить обратные вызовы mqtt и сохранить исходный обратный вызов on_message настолько чистым и читаемым, насколько это возможно, существует механизм обратных вызовов, который помогает пользователям генерировать обратные вызовы простым способом, как показано ниже.

@CallbackMechanism.make_callback("client1", "topic.split('/')[1] == 'callback'")
def callback_trigger(topic, payload):
    print("callback has been triggered")  
    print("do something")

Приведенный выше декоратор принимает первый аргумент в качестве идентификатора клиента mqtt, для которого пользователь хочет, чтобы был вызван обратный вызов, а следующий аргумент является выражением, которое, если оно оценивается как true, запускает обратный вызов.Если сервис / модуль состоит из нескольких обратных вызовов, которые должны запускаться из разных условий, это делает создание обратных вызовов простым и чистым с точки зрения пользователя.

Механизм обратного вызова - это класс, который оборачивает исходную функцию обратного вызова on_message, что делает его достаточно гибким для пользователя, чтобы использовать механизм для генерации обратных вызовов или инициировать обратные вызовы из исходной функции on_message, что опять-таки может привести к множественным if /еще условия и сложная функция, просто говорю.

Механизм обратного вызова

class CallbackMechanism:

    callbackFunctionsTriggers = {}

    @classmethod
    def wrap_on_message(cls, on_message_func):
        def wrapped_on_message(*args):
            client = args[0]
            msg = args[2]
            clientId = str(client._client_id)[2:-1]
            topic = msg.topic
            payload = str(msg.payload)[2:-1]
            on_message_func(topic, payload)
            for condition, callback in cls.callbackFunctionsTriggers[
                    clientId].items():
                if eval(condition):
                    callback(topic, payload)
        return wrapped_on_message

    @classmethod
    def make_callback(cls, clientId, condition):
        def decorator(callbackFunc):
            if clientId not in cls.callbackFunctionsTriggers:
                cls.callbackFunctionsTriggers[clientId] = {}
            cls.callbackFunctionsTriggers[clientId][condition] = callbackFunc

            return callbackFunc

        return decorator

Пользователь

@CallbackMechanism.wrap_on_message
def on_message(topic, payload):
    print("topic --> ", topic)
    print("payload --> ", payload)
    print("do anything")

@CallbackMechanism.make_callback("client1", "topic.split('/')[1] == 'callback'")
def callback_trigger(topic, payload):
    print("callback has been triggered")  
    print("do something")
  1. , если есть, скажем, 20-30 обратных вызововкоторые должны запускаться из разных условий, основанных на разных темах и полезных нагрузках, исходная функция on_message будет загрязнена сложным if / else и станет длинной функцией.Что вы думаете о вышеуказанном механизме?Может ли быть лучший подход к проблеме усложнения множественных условий обратного вызова и их вызова внутри одной функции?
  2. Этот механизм работает для функций уровня модуля.Но как заставить вышесказанное работать для методов экземпляра класса.Обратный вызов в приведенном ниже коде не запускается, так как ему нужен сам объект в качестве первого аргумента, который не может быть предоставлен через обернутый on_message.Так как заставить это работать через тот же механизм?Как передать аргумент self при срабатывании обратного вызова?Смотрите код ниже -
import CallbackMechanism  # the same class will be used by all modules for generating callbacks

class AnyClass:
    @CallbackMechanism.make_callback("client1", "topic.split('/')[2] == 'class'")
    def callback_inside_class(self, topic, payload):
        print("this is callback inside class")

anyClassObject = AnyClass()
...