mmrelay 1.1.3__py3-none-any.whl → 1.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mmrelay might be problematic. Click here for more details.

mmrelay/matrix_utils.py CHANGED
@@ -21,6 +21,18 @@ from nio import (
21
21
  from nio.events.room_events import RoomMemberEvent
22
22
  from PIL import Image
23
23
 
24
+ from mmrelay.constants.config import (
25
+ CONFIG_KEY_ACCESS_TOKEN,
26
+ CONFIG_KEY_HOMESERVER,
27
+ CONFIG_SECTION_MATRIX,
28
+ )
29
+ from mmrelay.constants.database import DEFAULT_MSGS_TO_KEEP
30
+ from mmrelay.constants.formats import (
31
+ DEFAULT_MATRIX_PREFIX,
32
+ DEFAULT_MESHTASTIC_PREFIX,
33
+ DETECTION_SENSOR_APP,
34
+ )
35
+ from mmrelay.constants.network import MILLISECONDS_PER_SECOND
24
36
  from mmrelay.db_utils import (
25
37
  get_message_map_by_matrix_event_id,
26
38
  prune_message_map,
@@ -37,14 +49,14 @@ logger = get_logger(name="matrix_utils")
37
49
 
38
50
  def _get_msgs_to_keep_config():
39
51
  """
40
- Retrieve the configured number of messages to retain for message mapping, supporting both current and legacy configuration formats.
52
+ Returns the configured number of messages to retain for message mapping, supporting both current and legacy configuration sections.
41
53
 
42
54
  Returns:
43
- int: The number of messages to keep in the database for message mapping (default is 500).
55
+ int: Number of messages to keep for message mapping; defaults to the predefined constant if not set.
44
56
  """
45
57
  global config
46
58
  if not config:
47
- return 500
59
+ return DEFAULT_MSGS_TO_KEEP
48
60
 
49
61
  msg_map_config = config.get("database", {}).get("msg_map", {})
50
62
 
@@ -58,26 +70,19 @@ def _get_msgs_to_keep_config():
58
70
  "Using 'db.msg_map' configuration (legacy). 'database.msg_map' is now the preferred format and 'db.msg_map' will be deprecated in a future version."
59
71
  )
60
72
 
61
- return msg_map_config.get("msgs_to_keep", 500)
73
+ return msg_map_config.get("msgs_to_keep", DEFAULT_MSGS_TO_KEEP)
62
74
 
63
75
 
64
76
  def _create_mapping_info(
65
77
  matrix_event_id, room_id, text, meshnet=None, msgs_to_keep=None
66
78
  ):
67
79
  """
68
- Constructs a dictionary containing metadata for mapping a Matrix event to a Meshtastic message in the message queue.
80
+ Create a metadata dictionary linking a Matrix event to a Meshtastic message for message mapping.
69
81
 
70
- Removes quoted lines from the message text and includes relevant identifiers and configuration for message retention. Returns `None` if required parameters are missing.
71
-
72
- Parameters:
73
- matrix_event_id: The Matrix event ID to map.
74
- room_id: The Matrix room ID where the event occurred.
75
- text: The message text to be mapped; quoted lines are removed.
76
- meshnet: Optional name of the target mesh network.
77
- msgs_to_keep: Optional number of messages to retain for mapping; uses configuration default if not provided.
82
+ Removes quoted lines from the message text and includes identifiers and message retention settings. Returns `None` if any required parameter is missing.
78
83
 
79
84
  Returns:
80
- dict: A dictionary with mapping information for use by the message queue, or `None` if required fields are missing.
85
+ dict: Mapping information for the message queue, or `None` if required fields are missing.
81
86
  """
82
87
  if not matrix_event_id or not room_id or not text:
83
88
  return None
@@ -94,16 +99,11 @@ def _create_mapping_info(
94
99
  }
95
100
 
96
101
 
97
- # Default prefix format constants
98
- DEFAULT_MESHTASTIC_PREFIX = "{display5}[M]: "
99
- DEFAULT_MATRIX_PREFIX = "[{long}/{mesh}]: "
100
-
101
-
102
102
  def get_interaction_settings(config):
103
103
  """
104
- Returns a dictionary indicating whether message reactions and replies are enabled based on the provided configuration.
104
+ Determine if message reactions and replies are enabled in the configuration.
105
105
 
106
- Supports both the new `message_interactions` structure and the legacy `relay_reactions` flag for backward compatibility. Defaults to disabling both features if not specified.
106
+ Checks for both the new `message_interactions` structure and the legacy `relay_reactions` flag for backward compatibility. Returns a dictionary with boolean values for `reactions` and `replies`, defaulting to both disabled if not specified.
107
107
  """
108
108
  if config is None:
109
109
  return {"reactions": False, "replies": False}
@@ -244,28 +244,19 @@ def get_meshtastic_prefix(config, display_name, user_id=None):
244
244
 
245
245
  def get_matrix_prefix(config, longname, shortname, meshnet_name):
246
246
  """
247
- Generate a formatted prefix for Meshtastic messages relayed to Matrix, using configurable templates and variable-length truncation for sender and mesh network names.
247
+ Generates a formatted prefix string for Meshtastic messages relayed to Matrix, based on configuration settings and sender/mesh network names.
248
+
249
+ The prefix format supports variable-length truncation for the sender and mesh network names using template variables (e.g., `{long4}` for the first 4 characters of the sender name). Returns an empty string if prefixing is disabled in the configuration.
248
250
 
249
251
  Parameters:
250
- config (dict): The application configuration dictionary.
251
252
  longname (str): Full Meshtastic sender name.
252
253
  shortname (str): Short Meshtastic sender name.
253
254
  meshnet_name (str): Name of the mesh network.
254
255
 
255
256
  Returns:
256
- str: The formatted prefix string if prefixing is enabled; otherwise, an empty string.
257
-
258
- Examples:
259
- Basic usage:
260
- get_matrix_prefix(config, "Alice", "Ali", "MyMesh")
261
- # Returns: "[Alice/MyMesh]: " (with default format)
262
-
263
- Custom format:
264
- config = {"matrix": {"prefix_format": "({long4}): "}}
265
- get_matrix_prefix(config, "Alice", "Ali", "MyMesh")
266
- # Returns: "(Alic): "
257
+ str: The formatted prefix string, or an empty string if prefixing is disabled.
267
258
  """
268
- matrix_config = config.get("matrix", {})
259
+ matrix_config = config.get(CONFIG_SECTION_MATRIX, {})
269
260
 
270
261
  # Enhanced debug logging for configuration troubleshooting
271
262
  logger.debug(
@@ -327,7 +318,7 @@ matrix_access_token = None
327
318
  bot_user_id = None
328
319
  bot_user_name = None # Detected upon logon
329
320
  bot_start_time = int(
330
- time.time() * 1000
321
+ time.time() * MILLISECONDS_PER_SECOND
331
322
  ) # Timestamp when the bot starts, used to filter out old messages
332
323
 
333
324
  logger = get_logger(name="Matrix")
@@ -372,11 +363,9 @@ def bot_command(command, event):
372
363
 
373
364
  async def connect_matrix(passed_config=None):
374
365
  """
375
- Establish a connection to the Matrix homeserver.
376
- Sets global matrix_client and detects the bot's display name.
366
+ Asynchronously connects to the Matrix homeserver, initializes the Matrix client, and retrieves the bot's device ID and display name.
377
367
 
378
- Args:
379
- passed_config: The configuration dictionary to use (will update global config)
368
+ If a configuration dictionary is provided, it updates the global configuration before connecting. Returns the initialized Matrix AsyncClient instance, or `None` if configuration is missing. Raises `ConnectionError` if SSL context creation fails.
380
369
  """
381
370
  global matrix_client, bot_user_name, matrix_homeserver, matrix_rooms, matrix_access_token, bot_user_id, config
382
371
 
@@ -390,9 +379,9 @@ async def connect_matrix(passed_config=None):
390
379
  return None
391
380
 
392
381
  # Extract Matrix configuration
393
- matrix_homeserver = config["matrix"]["homeserver"]
382
+ matrix_homeserver = config[CONFIG_SECTION_MATRIX][CONFIG_KEY_HOMESERVER]
394
383
  matrix_rooms = config["matrix_rooms"]
395
- matrix_access_token = config["matrix"]["access_token"]
384
+ matrix_access_token = config[CONFIG_SECTION_MATRIX][CONFIG_KEY_ACCESS_TOKEN]
396
385
  bot_user_id = config["matrix"]["bot_user_id"]
397
386
 
398
387
  # Check if client already exists
@@ -400,7 +389,11 @@ async def connect_matrix(passed_config=None):
400
389
  return matrix_client
401
390
 
402
391
  # Create SSL context using certifi's certificates
403
- ssl_context = ssl.create_default_context(cafile=certifi.where())
392
+ try:
393
+ ssl_context = ssl.create_default_context(cafile=certifi.where())
394
+ except Exception as e:
395
+ logger.error(f"Failed to create SSL context: {e}")
396
+ raise ConnectionError(f"SSL context creation failed: {e}") from e
404
397
 
405
398
  # Initialize the Matrix client with custom SSL context
406
399
  client_config = AsyncClientConfig(encryption_enabled=False)
@@ -487,9 +480,9 @@ async def matrix_relay(
487
480
  reply_to_event_id=None,
488
481
  ):
489
482
  """
490
- Relays a message from Meshtastic to a Matrix room, supporting replies and message mapping for interactions.
483
+ Relay a message from the Meshtastic network to a Matrix room, supporting replies, emotes, emoji reactions, and message mapping for future interactions.
491
484
 
492
- If `reply_to_event_id` is provided, sends the message as a Matrix reply, formatting the content to include quoted original text and appropriate Matrix reply relations. When message interactions (reactions or replies) are enabled in the configuration, stores a mapping between the Meshtastic message ID and the resulting Matrix event ID to enable cross-referencing for future interactions. Prunes old message mappings based on configuration to limit storage.
485
+ If a reply target is specified, formats the message as a Matrix reply with quoted original content. When message interactions (reactions or replies) are enabled, stores a mapping between the Meshtastic message ID and the resulting Matrix event ID to support cross-network interactions. Prunes old message mappings according to configuration to limit storage.
493
486
 
494
487
  Parameters:
495
488
  room_id (str): The Matrix room ID to send the message to.
@@ -504,9 +497,6 @@ async def matrix_relay(
504
497
  emote (bool, optional): Whether to send the message as an emote.
505
498
  emoji (bool, optional): Whether the message is an emoji reaction.
506
499
  reply_to_event_id (str, optional): The Matrix event ID being replied to, if sending a reply.
507
-
508
- Returns:
509
- None
510
500
  """
511
501
  global config
512
502
 
@@ -540,8 +530,8 @@ async def matrix_relay(
540
530
  "Using 'db.msg_map' configuration (legacy). 'database.msg_map' is now the preferred format and 'db.msg_map' will be deprecated in a future version."
541
531
  )
542
532
  msgs_to_keep = msg_map_config.get(
543
- "msgs_to_keep", 500
544
- ) # Default is 500 if not specified
533
+ "msgs_to_keep", DEFAULT_MSGS_TO_KEEP
534
+ ) # Default from constants
545
535
 
546
536
  try:
547
537
  # Always use our own local meshnet_name for outgoing events
@@ -875,9 +865,9 @@ async def on_room_message(
875
865
  event: Union[RoomMessageText, RoomMessageNotice, ReactionEvent, RoomMessageEmote],
876
866
  ) -> None:
877
867
  """
878
- Handle incoming Matrix room messages, reactions, and replies, relaying them to Meshtastic as appropriate.
868
+ Asynchronously handles incoming Matrix room messages, reactions, and replies, relaying them to Meshtastic as appropriate.
879
869
 
880
- This function processes Matrix events—including text messages, reactions, and replies—received in configured Matrix rooms. It relays supported messages to the Meshtastic mesh network if broadcasting is enabled, applying message mapping for cross-referencing when reactions or replies are enabled. The function prevents relaying of reactions to reactions, ignores messages from the bot itself or those sent before the bot started, and integrates with plugins for command and message handling. Only messages that are not commands or handled by plugins are forwarded to Meshtastic, with proper formatting and truncation as needed.
870
+ Processes Matrix events—including text messages, reactions, and replies—in configured rooms. Relays supported messages to the Meshtastic mesh network if broadcasting is enabled, applying message mapping for cross-referencing when reactions or replies are enabled. Ignores messages from the bot itself, messages sent before the bot started, and reactions to reactions. Integrates with plugins for command and message handling; only messages not handled by plugins or identified as commands are forwarded to Meshtastic, with appropriate formatting and truncation. Handles special cases for relaying messages and reactions from remote mesh networks and detection sensor data.
881
871
  """
882
872
  # Importing here to avoid circular imports and to keep logic consistent
883
873
  # Note: We do not call store_message_map directly here for inbound matrix->mesh messages.
@@ -1227,7 +1217,7 @@ async def on_room_message(
1227
1217
  if not found_matching_plugin:
1228
1218
  if config["meshtastic"]["broadcast_enabled"]:
1229
1219
  portnum = event.source["content"].get("meshtastic_portnum")
1230
- if portnum == "DETECTION_SENSOR_APP":
1220
+ if portnum == DETECTION_SENSOR_APP:
1231
1221
  # If detection_sensor is enabled, forward this data as detection sensor data
1232
1222
  if config["meshtastic"].get("detection_sensor", False):
1233
1223
  success = queue_message(