Guest User

hn-comment

a guest
May 1st, 2025
298
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.25 KB | Source Code | 0 0
  1. <think>
  2. ...
  3. </think>
  4.  
  5.  
  6.  
  7. 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.
  8.  
  9. ---
  10.  
  11. ### โœ… Key Components
  12.  
  13. - **Node Class**: Represents a node in the trie with:
  14.   - Children: dictionary mapping topic parts.
  15.   - Wildcard nodes (`plus_wildcard`, `hash_wildcard`).
  16.   - List of registered handler functions.
  17.  
  18. - **MQTTRegistry Class**:
  19.   - Stores root node and manages adding handlers to patterns.
  20.   - Implements a recursive DFS-based match logic that supports wildcard matching for MQTT topics.
  21.  
  22. - **Decorator**: A function `@mqtt_handler(topic_pattern)` used to register functions as topic handlers with their corresponding pattern.
  23.  
  24. ---
  25.  
  26. ### ๐Ÿง  Matching Logic
  27.  
  28. - The `+` wildcard matches exactly one level of the topic (e.g., `a/+/b`).
  29. - The `#` wildcard matches any number of levels, but **must appear at the end** of a pattern.
  30. - During matching, we explore all possible paths that can match the incoming topic.
  31.  
  32. ---
  33.  
  34. ### ๐Ÿ“ฆ Complete Implementation
  35.  
  36. ```python
  37. class Node:
  38.     def __init__(self):
  39.         self.children = {}
  40.         self.plus_wildcard = None
  41.         self.hash_wildcard = None
  42.         self.handlers = []
  43.  
  44. class MQTTRegistry:
  45.     def __init__(self):
  46.         self.root = Node()
  47.  
  48.     def add_handler(self, topic_pattern, handler_func):
  49.         parts = self.split_topic(topic_pattern)
  50.         current_node = self.root
  51.         i = 0
  52.  
  53.         while i < len(parts):
  54.             part = parts[i]
  55.             if part == '+':
  56.                 # Handle '+' wildcard: move to the plus_wildcard node
  57.                 if not current_node.plus_wildcard:
  58.                     current_node.plus_wildcard = Node()
  59.                 current_node = current_node.plus_wildcard
  60.                 i += 1
  61.             elif part == '#':
  62.                 # Handle '#' wildcard: match any remaining parts
  63.                 if not current_node.hash_wildcard:
  64.                     current_node.hash_wildcard = Node()
  65.                 current_node = current_node.hash_wildcard
  66.                 i += 1
  67.             else:
  68.                 # Regular topic level
  69.                 if part not in current_node.children:
  70.                     current_node.children[part] = Node()
  71.                 current_node = current_node.children[part]
  72.                 i += 1
  73.  
  74.         # Register the handler at this node
  75.         current_node.handlers.append(handler_func)
  76.  
  77.     def split_topic(self, topic):
  78.         return topic.split('/')
  79.  
  80.     def match_topic(self, topic):
  81.         parts = self.split_topic(topic)
  82.         matched_handlers = []
  83.  
  84.         def dfs(node, index):
  85.             if index == len(parts):
  86.                 # All parts of the incoming topic have been processed
  87.                 matched_handlers.extend(node.handlers)
  88.                 return
  89.  
  90.             current_part = parts[index]
  91.  
  92.             # 1. Check for plus wildcard (match any single part)
  93.             if node.plus_wildcard:
  94.                 dfs(node.plus_wildcard, index + 1)
  95.  
  96.             # 2. Check for hash wildcard (match any remaining parts)
  97.             if node.hash_wildcard:
  98.                 matched_handlers.extend(node.hash_wildcard.handlers)
  99.  
  100.             # 3. Check for exact match with current topic part
  101.             if current_part in node.children:
  102.                 dfs(node.children[current_part], index + 1)
  103.  
  104.         dfs(self.root, 0)
  105.         return matched_handlers
  106.  
  107. # Decorator to register handlers for MQTT topics
  108. def mqtt_handler(topic_pattern):
  109.     def decorator(func):
  110.         registry.add_handler(topic_pattern, func)
  111.         return func
  112.     return decorator
  113.  
  114. # Initialize the registry
  115. registry = MQTTRegistry()
  116. ```
  117.  
  118. ---
  119.  
  120. ### ๐Ÿงช Example Usage
  121.  
  122. ```python
  123. @mqtt_handler("a/+/b")
  124. def handler1(msg):
  125.     print(f"Handler 1: {msg}")
  126.  
  127. @mqtt_handler("a/#")
  128. def handler2(msg):
  129.     print(f"Handler 2: {msg}")
  130.  
  131. @mqtt_handler("c/d")
  132. def handler3(msg):
  133.     print(f"Handler 3: {msg}")
  134.  
  135. # Simulate message dispatch
  136. message_topic = "a/x/b"
  137. message_data = "This is a test message."
  138.  
  139. print(f"\nProcessing topic: {message_topic}")
  140. matched_handlers = registry.match_topic(message_topic)
  141.  
  142. for handler in matched_handlers:
  143.     handler(message_data)
  144. ```
  145.  
  146. ---
  147.  
  148. ### ๐Ÿ“Œ Expected Output
  149.  
  150. ```
  151. Processing topic: a/x/b
  152. Handler 1: This is a test message.
  153. Handler 2: This is a test message.
  154. ```
  155.  
  156. This demonstrates how both `a/+/b` and `a/#` match the incoming topic `"a/x/b"`.
  157.  
  158. ---
  159.  
  160. ### โš ๏ธ Notes for Production
  161.  
  162. - The current `match_topic` logic does not fully respect MQTT rules (e.g., `#` must be at the end of a pattern).
  163. - For production, consider:
  164.   - Enforcing that `#` can only appear once and at the end.
  165.   - Improving DFS to track which parts have been processed for exact match with wildcards.
  166.  
  167. ---
  168.  
  169. ### ๐Ÿ”— Summary
  170.  
  171. 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