Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <think>
- ...
- </think>
- To implement an MQTT topic handler using a trie structure in Python, we define a `Node` class to represent each level of the topic hierarchy. A `MQTTRegistry` manages these nodes and registers functions to match specific patterns (with wildcards like `+` and `#`). Finally, we create a decorator that allows users to register handlers for MQTT topics.
- ---
- ### โ Key Components
- - **Node Class**: Represents a node in the trie with:
- - Children: dictionary mapping topic parts.
- - Wildcard nodes (`plus_wildcard`, `hash_wildcard`).
- - List of registered handler functions.
- - **MQTTRegistry Class**:
- - Stores root node and manages adding handlers to patterns.
- - Implements a recursive DFS-based match logic that supports wildcard matching for MQTT topics.
- - **Decorator**: A function `@mqtt_handler(topic_pattern)` used to register functions as topic handlers with their corresponding pattern.
- ---
- ### ๐ง Matching Logic
- - The `+` wildcard matches exactly one level of the topic (e.g., `a/+/b`).
- - The `#` wildcard matches any number of levels, but **must appear at the end** of a pattern.
- - During matching, we explore all possible paths that can match the incoming topic.
- ---
- ### ๐ฆ Complete Implementation
- ```python
- class Node:
- def __init__(self):
- self.children = {}
- self.plus_wildcard = None
- self.hash_wildcard = None
- self.handlers = []
- class MQTTRegistry:
- def __init__(self):
- self.root = Node()
- def add_handler(self, topic_pattern, handler_func):
- parts = self.split_topic(topic_pattern)
- current_node = self.root
- i = 0
- while i < len(parts):
- part = parts[i]
- if part == '+':
- # Handle '+' wildcard: move to the plus_wildcard node
- if not current_node.plus_wildcard:
- current_node.plus_wildcard = Node()
- current_node = current_node.plus_wildcard
- i += 1
- elif part == '#':
- # Handle '#' wildcard: match any remaining parts
- if not current_node.hash_wildcard:
- current_node.hash_wildcard = Node()
- current_node = current_node.hash_wildcard
- i += 1
- else:
- # Regular topic level
- if part not in current_node.children:
- current_node.children[part] = Node()
- current_node = current_node.children[part]
- i += 1
- # Register the handler at this node
- current_node.handlers.append(handler_func)
- def split_topic(self, topic):
- return topic.split('/')
- def match_topic(self, topic):
- parts = self.split_topic(topic)
- matched_handlers = []
- def dfs(node, index):
- if index == len(parts):
- # All parts of the incoming topic have been processed
- matched_handlers.extend(node.handlers)
- return
- current_part = parts[index]
- # 1. Check for plus wildcard (match any single part)
- if node.plus_wildcard:
- dfs(node.plus_wildcard, index + 1)
- # 2. Check for hash wildcard (match any remaining parts)
- if node.hash_wildcard:
- matched_handlers.extend(node.hash_wildcard.handlers)
- # 3. Check for exact match with current topic part
- if current_part in node.children:
- dfs(node.children[current_part], index + 1)
- dfs(self.root, 0)
- return matched_handlers
- # Decorator to register handlers for MQTT topics
- def mqtt_handler(topic_pattern):
- def decorator(func):
- registry.add_handler(topic_pattern, func)
- return func
- return decorator
- # Initialize the registry
- registry = MQTTRegistry()
- ```
- ---
- ### ๐งช Example Usage
- ```python
- @mqtt_handler("a/+/b")
- def handler1(msg):
- print(f"Handler 1: {msg}")
- @mqtt_handler("a/#")
- def handler2(msg):
- print(f"Handler 2: {msg}")
- @mqtt_handler("c/d")
- def handler3(msg):
- print(f"Handler 3: {msg}")
- # Simulate message dispatch
- message_topic = "a/x/b"
- message_data = "This is a test message."
- print(f"\nProcessing topic: {message_topic}")
- matched_handlers = registry.match_topic(message_topic)
- for handler in matched_handlers:
- handler(message_data)
- ```
- ---
- ### ๐ Expected Output
- ```
- Processing topic: a/x/b
- Handler 1: This is a test message.
- Handler 2: This is a test message.
- ```
- This demonstrates how both `a/+/b` and `a/#` match the incoming topic `"a/x/b"`.
- ---
- ### โ ๏ธ Notes for Production
- - The current `match_topic` logic does not fully respect MQTT rules (e.g., `#` must be at the end of a pattern).
- - For production, consider:
- - Enforcing that `#` can only appear once and at the end.
- - Improving DFS to track which parts have been processed for exact match with wildcards.
- ---
- ### ๐ Summary
- This implementation provides a clean way to register MQTT topic handlers using a trie structure. It supports both single-level (`+`) and multi-level (`#`) wildcards, making it suitable for real-time message routing in systems like IoT or event-driven architectures.
Advertisement
Add Comment
Please, Sign In to add comment