mmrelay 1.2.2__tar.gz → 1.2.4__tar.gz
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-1.2.2/src/mmrelay.egg-info → mmrelay-1.2.4}/PKG-INFO +2 -2
- {mmrelay-1.2.2 → mmrelay-1.2.4}/requirements.txt +2 -2
- {mmrelay-1.2.2 → mmrelay-1.2.4}/setup.py +1 -1
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/__init__.py +1 -1
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/cli.py +27 -30
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/config.py +14 -16
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/constants/queue.py +4 -1
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/e2ee_utils.py +7 -2
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/log_utils.py +29 -8
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/main.py +14 -5
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/matrix_utils.py +73 -73
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/meshtastic_utils.py +20 -21
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/message_queue.py +16 -15
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/base_plugin.py +7 -7
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/mesh_relay_plugin.py +16 -17
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/setup_utils.py +5 -5
- mmrelay-1.2.4/src/mmrelay/tools/sample-docker-compose-prebuilt.yaml +30 -0
- mmrelay-1.2.4/src/mmrelay/tools/sample-docker-compose.yaml +30 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/windows_utils.py +1 -1
- {mmrelay-1.2.2 → mmrelay-1.2.4/src/mmrelay.egg-info}/PKG-INFO +2 -2
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay.egg-info/requires.txt +1 -1
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_auth_flow_fixes.py +5 -8
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_base_plugin.py +4 -4
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_e2ee_unified.py +153 -15
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_log_utils.py +68 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_main_entry_point.py +1 -1
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_matrix_utils.py +604 -151
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_matrix_utils_error_handling.py +3 -3
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_mesh_relay_plugin.py +86 -20
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_performance_stress.py +10 -15
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_plugin_loader.py +141 -3
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_setup_utils.py +2 -2
- mmrelay-1.2.2/src/mmrelay/tools/sample-docker-compose-prebuilt.yaml +0 -19
- mmrelay-1.2.2/src/mmrelay/tools/sample-docker-compose.yaml +0 -19
- {mmrelay-1.2.2 → mmrelay-1.2.4}/LICENSE +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/MANIFEST.in +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/README.md +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/pyproject.toml +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/setup.cfg +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/__main__.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/cli_utils.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/constants/__init__.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/constants/app.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/constants/config.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/constants/database.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/constants/formats.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/constants/messages.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/constants/network.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/db_utils.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugin_loader.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/__init__.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/debug_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/drop_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/health_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/help_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/map_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/nodes_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/ping_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/telemetry_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/plugins/weather_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/runtime_utils.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/tools/__init__.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/tools/mmrelay.service +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/tools/sample.env +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay/tools/sample_config.yaml +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay.egg-info/SOURCES.txt +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay.egg-info/dependency_links.txt +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay.egg-info/entry_points.txt +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/src/mmrelay.egg-info/top_level.txt +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_async_patterns.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_cli.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_cli_diagnose.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_cli_edge_cases.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_cli_utils.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_cli_windows_integration.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_config.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_config_checker.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_config_edge_cases.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_constants.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_core_utils_coverage.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_db_utils.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_db_utils_edge_cases.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_debug_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_drop_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_e2ee_encryption.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_e2ee_integration.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_e2ee_runner.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_error_boundaries.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_health_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_help_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_imports.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_integration_scenarios.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_main.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_map_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_matrix_utils_edge_cases.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_meshtastic_broadcast_enabled.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_meshtastic_utils.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_meshtastic_utils_edge_cases.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_message_queue.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_message_queue_edge_cases.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_network_reliability.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_nodes_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_patch_coverage_improvements.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_ping_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_plugin_loader_edge_cases.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_prefix_customization.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_runtime_no_errors.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_setup_utils_edge_cases.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_setup_utils_execstart_improvements.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_setup_utils_systemctl.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_telemetry_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_tools_init.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_weather_plugin.py +0 -0
- {mmrelay-1.2.2 → mmrelay-1.2.4}/tests/test_windows_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mmrelay
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Summary: Bridge between Meshtastic mesh networks and Matrix chat rooms
|
|
5
5
|
Home-page: https://github.com/jeremiah-k/meshtastic-matrix-relay
|
|
6
6
|
Author: Geoff Whittington, Jeremiah K., and contributors
|
|
@@ -18,7 +18,7 @@ Classifier: Topic :: Communications
|
|
|
18
18
|
Requires-Python: >=3.9
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: meshtastic>=2.
|
|
21
|
+
Requires-Dist: meshtastic>=2.7.3
|
|
22
22
|
Requires-Dist: Pillow==11.3.0
|
|
23
23
|
Requires-Dist: matrix-nio==0.25.2
|
|
24
24
|
Requires-Dist: matplotlib==3.10.1
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
meshtastic>=2.
|
|
1
|
+
meshtastic>=2.7.3
|
|
2
2
|
Pillow==11.3.0
|
|
3
3
|
matrix-nio==0.25.2
|
|
4
4
|
matplotlib==3.10.1
|
|
@@ -16,7 +16,7 @@ setuptools>=80.9.0 # Required for console script entry points and Windows compa
|
|
|
16
16
|
# Testing and coverage
|
|
17
17
|
coverage==7.10.7
|
|
18
18
|
pytest==8.4.2
|
|
19
|
-
pytest-cov==
|
|
19
|
+
pytest-cov==7.0.0
|
|
20
20
|
pytest-asyncio==1.2.0
|
|
21
21
|
pytest-env==1.1.5
|
|
22
22
|
pytest-timeout==2.4.0
|
|
@@ -238,11 +238,11 @@ def print_version():
|
|
|
238
238
|
def _validate_e2ee_dependencies():
|
|
239
239
|
"""
|
|
240
240
|
Check whether end-to-end encryption (E2EE) is usable on the current platform.
|
|
241
|
-
|
|
241
|
+
|
|
242
242
|
Returns:
|
|
243
243
|
bool: True if the platform is supported and required E2EE libraries can be imported;
|
|
244
244
|
False otherwise.
|
|
245
|
-
|
|
245
|
+
|
|
246
246
|
Notes:
|
|
247
247
|
- This function performs only local checks (platform and importability) and does not perform
|
|
248
248
|
network I/O.
|
|
@@ -1499,13 +1499,13 @@ def handle_auth_logout(args):
|
|
|
1499
1499
|
def handle_service_command(args):
|
|
1500
1500
|
"""
|
|
1501
1501
|
Dispatch service-related subcommands.
|
|
1502
|
-
|
|
1502
|
+
|
|
1503
1503
|
Currently supports the "install" subcommand which imports and runs mmrelay.setup_utils.install_service().
|
|
1504
1504
|
Returns 0 on successful installation, 1 on failure or for unknown subcommands.
|
|
1505
|
-
|
|
1505
|
+
|
|
1506
1506
|
Parameters:
|
|
1507
1507
|
args: argparse.Namespace with a `service_command` attribute indicating the requested action.
|
|
1508
|
-
|
|
1508
|
+
|
|
1509
1509
|
Returns:
|
|
1510
1510
|
int: Exit code (0 on success, 1 on error).
|
|
1511
1511
|
"""
|
|
@@ -1524,15 +1524,15 @@ def handle_service_command(args):
|
|
|
1524
1524
|
|
|
1525
1525
|
def _diagnose_config_paths(args):
|
|
1526
1526
|
"""
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1527
|
+
Prints a diagnostic summary of resolved configuration file search paths and their directory accessibility.
|
|
1528
|
+
|
|
1529
|
+
Each candidate config path is printed with a status icon:
|
|
1530
1530
|
- ✅ directory exists and is writable
|
|
1531
1531
|
- ⚠️ directory exists but is not writable
|
|
1532
1532
|
- ❌ directory does not exist
|
|
1533
|
-
|
|
1533
|
+
|
|
1534
1534
|
Parameters:
|
|
1535
|
-
args (argparse.Namespace):
|
|
1535
|
+
args (argparse.Namespace): CLI arguments used to determine the ordered list of candidate config paths (passed to get_config_paths).
|
|
1536
1536
|
"""
|
|
1537
1537
|
print("1. Testing configuration paths...")
|
|
1538
1538
|
from mmrelay.config import get_config_paths
|
|
@@ -1551,11 +1551,11 @@ def _diagnose_config_paths(args):
|
|
|
1551
1551
|
def _diagnose_sample_config_accessibility():
|
|
1552
1552
|
"""
|
|
1553
1553
|
Check availability of the bundled sample configuration and print a short diagnostic.
|
|
1554
|
-
|
|
1554
|
+
|
|
1555
1555
|
Performs two non-destructive checks and prints human-readable results:
|
|
1556
1556
|
1) Verifies whether the sample config file exists at the path returned by mmrelay.tools.get_sample_config_path().
|
|
1557
1557
|
2) Attempts to read the embedded resource "sample_config.yaml" from the mmrelay.tools package via importlib.resources and reports success and the content length.
|
|
1558
|
-
|
|
1558
|
+
|
|
1559
1559
|
Returns:
|
|
1560
1560
|
bool: True if a filesystem sample config exists at the resolved path; False otherwise.
|
|
1561
1561
|
"""
|
|
@@ -1586,18 +1586,15 @@ def _diagnose_sample_config_accessibility():
|
|
|
1586
1586
|
|
|
1587
1587
|
def _diagnose_platform_specific(args):
|
|
1588
1588
|
"""
|
|
1589
|
-
Run platform-specific diagnostic checks.
|
|
1590
|
-
|
|
1591
|
-
On Windows,
|
|
1592
|
-
|
|
1593
|
-
platforms this reports that platform-specific tests are not required.
|
|
1594
|
-
|
|
1589
|
+
Run platform-specific diagnostic checks and print a concise report.
|
|
1590
|
+
|
|
1591
|
+
On Windows, executes Windows-specific requirement checks and a configuration-generation test using the provided CLI arguments; on non-Windows platforms, reports that platform-specific tests are not required.
|
|
1592
|
+
|
|
1595
1593
|
Parameters:
|
|
1596
|
-
args (argparse.Namespace):
|
|
1597
|
-
|
|
1598
|
-
|
|
1594
|
+
args (argparse.Namespace): CLI arguments forwarded to the Windows configuration-generation test (used only when running on Windows).
|
|
1595
|
+
|
|
1599
1596
|
Returns:
|
|
1600
|
-
bool: True if
|
|
1597
|
+
bool: `True` if Windows checks were executed (running on Windows), `False` otherwise.
|
|
1601
1598
|
"""
|
|
1602
1599
|
print("3. Platform-specific diagnostics...")
|
|
1603
1600
|
import sys
|
|
@@ -1704,7 +1701,7 @@ logging:
|
|
|
1704
1701
|
def _diagnose_minimal_config_template():
|
|
1705
1702
|
"""
|
|
1706
1703
|
Validate the built-in minimal YAML configuration template and print a concise pass/fail status.
|
|
1707
|
-
|
|
1704
|
+
|
|
1708
1705
|
Attempts to parse the string returned by _get_minimal_config_template() using yaml.safe_load. Prints a single-line result showing a ✅ with the template character length when the template is valid YAML, or a ❌ with the YAML parsing error when invalid. This is a non-destructive diagnostic helper that prints output and does not return a value.
|
|
1709
1706
|
"""
|
|
1710
1707
|
print("4. Testing minimal config template fallback...")
|
|
@@ -1720,15 +1717,15 @@ def _diagnose_minimal_config_template():
|
|
|
1720
1717
|
|
|
1721
1718
|
def handle_config_diagnose(args):
|
|
1722
1719
|
"""
|
|
1723
|
-
Run non-destructive diagnostics for the MMRelay configuration subsystem and print a human-readable report.
|
|
1724
|
-
|
|
1725
|
-
Performs four checks: resolves candidate
|
|
1726
|
-
|
|
1720
|
+
Run a set of non-destructive diagnostics for the MMRelay configuration subsystem and print a concise, human-readable report.
|
|
1721
|
+
|
|
1722
|
+
Performs four checks without modifying user files: (1) resolves and reports candidate configuration file paths and their directory accessibility, (2) verifies availability and readability of the packaged sample configuration, (3) executes platform-specific diagnostics (Windows checks when applicable), and (4) validates the built-in minimal YAML configuration template. Results and actionable guidance are written to stdout/stderr; additional Windows-specific guidance may be printed to stderr on unexpected failures.
|
|
1723
|
+
|
|
1727
1724
|
Parameters:
|
|
1728
|
-
args (argparse.Namespace): Parsed CLI arguments used to
|
|
1729
|
-
|
|
1725
|
+
args (argparse.Namespace): Parsed CLI arguments used to determine configuration search paths and to control platform-specific diagnostic behavior.
|
|
1726
|
+
|
|
1730
1727
|
Returns:
|
|
1731
|
-
int: Exit code
|
|
1728
|
+
int: Exit code where `0` indicates diagnostics completed successfully and `1` indicates a failure occurred (an error summary is printed to stderr).
|
|
1732
1729
|
"""
|
|
1733
1730
|
print("MMRelay Configuration System Diagnostics")
|
|
1734
1731
|
print("=" * 40)
|
|
@@ -196,14 +196,12 @@ def get_log_dir():
|
|
|
196
196
|
|
|
197
197
|
def get_e2ee_store_dir():
|
|
198
198
|
"""
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
On Linux and macOS
|
|
202
|
-
|
|
203
|
-
platformdirs.user_data_dir(APP_NAME, APP_AUTHOR)/store.
|
|
204
|
-
|
|
199
|
+
Get the absolute path to the application's end-to-end encryption (E2EE) data store directory, creating it if necessary.
|
|
200
|
+
|
|
201
|
+
On Linux and macOS the directory is located under the application base directory; on Windows it uses the configured custom data directory when set, otherwise the platform-specific user data directory. The directory will be created if it does not exist.
|
|
202
|
+
|
|
205
203
|
Returns:
|
|
206
|
-
str: Absolute path to the ensured store directory.
|
|
204
|
+
store_dir (str): Absolute path to the ensured E2EE store directory.
|
|
207
205
|
"""
|
|
208
206
|
if sys.platform in ["linux", "darwin"]:
|
|
209
207
|
# Use ~/.mmrelay/store/ for Linux and Mac
|
|
@@ -388,12 +386,12 @@ def is_e2ee_enabled(config):
|
|
|
388
386
|
def check_e2ee_enabled_silently(args=None):
|
|
389
387
|
"""
|
|
390
388
|
Check silently whether End-to-End Encryption (E2EE) is enabled in the first readable configuration file.
|
|
391
|
-
|
|
389
|
+
|
|
392
390
|
Searches candidate configuration paths returned by get_config_paths(args) in priority order, loads the first readable YAML file, and returns True if that configuration enables E2EE (via is_e2ee_enabled). I/O and YAML parsing errors are ignored and the function continues to the next candidate. On Windows this always returns False.
|
|
393
|
-
|
|
391
|
+
|
|
394
392
|
Parameters:
|
|
395
393
|
args (optional): Parsed command-line arguments that can influence config search order.
|
|
396
|
-
|
|
394
|
+
|
|
397
395
|
Returns:
|
|
398
396
|
bool: True if E2EE is enabled in the first valid configuration file found; otherwise False.
|
|
399
397
|
"""
|
|
@@ -493,16 +491,16 @@ def load_credentials():
|
|
|
493
491
|
def save_credentials(credentials):
|
|
494
492
|
"""
|
|
495
493
|
Persist a JSON-serializable credentials mapping to <base_dir>/credentials.json.
|
|
496
|
-
|
|
494
|
+
|
|
497
495
|
Writes the provided credentials (a JSON-serializable mapping) to the application's
|
|
498
496
|
base configuration directory as credentials.json, creating the base directory if
|
|
499
497
|
necessary. On Unix-like systems the file permissions are adjusted to be
|
|
500
498
|
restrictive (0o600) when possible. I/O and permission errors are caught and
|
|
501
499
|
logged; the function does not raise them.
|
|
502
|
-
|
|
500
|
+
|
|
503
501
|
Parameters:
|
|
504
502
|
credentials (dict): JSON-serializable mapping of credentials to persist.
|
|
505
|
-
|
|
503
|
+
|
|
506
504
|
Returns:
|
|
507
505
|
None
|
|
508
506
|
"""
|
|
@@ -822,18 +820,18 @@ def load_config(config_file=None, args=None):
|
|
|
822
820
|
def validate_yaml_syntax(config_content, config_path):
|
|
823
821
|
"""
|
|
824
822
|
Validate YAML text for syntax and common style issues, parse it with PyYAML, and return results.
|
|
825
|
-
|
|
823
|
+
|
|
826
824
|
Performs lightweight line-based checks for frequent mistakes (using '=' instead of ':'
|
|
827
825
|
for mappings and non-standard boolean words like 'yes'/'no' or 'on'/'off') and then
|
|
828
826
|
attempts to parse the content with yaml.safe_load. If only style warnings are found,
|
|
829
827
|
parsing is considered successful and warnings are returned; if parsing fails or true
|
|
830
828
|
syntax errors are detected, a detailed error message is returned that references
|
|
831
829
|
config_path to identify the source.
|
|
832
|
-
|
|
830
|
+
|
|
833
831
|
Parameters:
|
|
834
832
|
config_content (str): Raw YAML text to validate.
|
|
835
833
|
config_path (str): Path or label used in error messages to identify the source of the content.
|
|
836
|
-
|
|
834
|
+
|
|
837
835
|
Returns:
|
|
838
836
|
tuple:
|
|
839
837
|
is_valid (bool): True if YAML parsed successfully (style warnings allowed), False on syntax/parsing error.
|
|
@@ -6,7 +6,10 @@ delays, size limits, and water marks for queue management.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
# Message timing constants
|
|
9
|
-
DEFAULT_MESSAGE_DELAY =
|
|
9
|
+
DEFAULT_MESSAGE_DELAY = (
|
|
10
|
+
2.5 # Set above the 2.0s firmware limit to prevent message dropping
|
|
11
|
+
)
|
|
12
|
+
MINIMUM_MESSAGE_DELAY = 2.1 # Minimum delay enforced to stay above firmware limit
|
|
10
13
|
|
|
11
14
|
# Queue size management
|
|
12
15
|
MAX_QUEUE_SIZE = 500
|
|
@@ -80,8 +80,13 @@ def get_e2ee_status(
|
|
|
80
80
|
importlib.import_module("olm")
|
|
81
81
|
|
|
82
82
|
if os.getenv("MMRELAY_TESTING") != "1":
|
|
83
|
-
importlib.import_module("nio.crypto")
|
|
84
|
-
|
|
83
|
+
nio_crypto = importlib.import_module("nio.crypto")
|
|
84
|
+
if not hasattr(nio_crypto, "OlmDevice"):
|
|
85
|
+
raise ImportError("nio.crypto.OlmDevice is unavailable")
|
|
86
|
+
|
|
87
|
+
nio_store = importlib.import_module("nio.store")
|
|
88
|
+
if not hasattr(nio_store, "SqliteStore"):
|
|
89
|
+
raise ImportError("nio.store.SqliteStore is unavailable")
|
|
85
90
|
|
|
86
91
|
status["dependencies_installed"] = True
|
|
87
92
|
except ImportError:
|
|
@@ -69,14 +69,13 @@ _COMPONENT_LOGGERS = {
|
|
|
69
69
|
|
|
70
70
|
def configure_component_debug_logging():
|
|
71
71
|
"""
|
|
72
|
-
Configure log levels for external component loggers based on config
|
|
72
|
+
Configure log levels and handlers for external component loggers based on config.
|
|
73
73
|
|
|
74
|
-
Reads
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
- string: interpret as a logging level name (case-insensitive); invalid names fall back to DEBUG
|
|
74
|
+
Reads `config["logging"]["debug"]` and for each component:
|
|
75
|
+
- If enabled (True or a valid log level string), sets the component's loggers to the specified level and attaches the main application's handlers to them. This makes component logs appear in the console and log file.
|
|
76
|
+
- If disabled (falsy or missing), silences the component by setting its loggers to a level higher than CRITICAL.
|
|
78
77
|
|
|
79
|
-
This function
|
|
78
|
+
This function runs only once. It is not thread-safe and should be called early in the application startup, after the main logger is configured but before other modules are imported.
|
|
80
79
|
"""
|
|
81
80
|
global _component_debug_configured, config
|
|
82
81
|
|
|
@@ -84,7 +83,22 @@ def configure_component_debug_logging():
|
|
|
84
83
|
if _component_debug_configured or config is None:
|
|
85
84
|
return
|
|
86
85
|
|
|
87
|
-
|
|
86
|
+
# Get the main application logger and its handlers to attach to component loggers
|
|
87
|
+
main_logger = logging.getLogger(APP_DISPLAY_NAME)
|
|
88
|
+
main_handlers = main_logger.handlers
|
|
89
|
+
debug_settings = config.get("logging", {}).get("debug")
|
|
90
|
+
|
|
91
|
+
# Ensure debug_config is a dictionary, handling malformed configs gracefully
|
|
92
|
+
if isinstance(debug_settings, dict):
|
|
93
|
+
debug_config = debug_settings
|
|
94
|
+
else:
|
|
95
|
+
if debug_settings is not None:
|
|
96
|
+
main_logger.warning(
|
|
97
|
+
"Debug logging section is not a dictionary. "
|
|
98
|
+
"All component debug logging will be disabled. "
|
|
99
|
+
"Check your config.yaml debug section formatting."
|
|
100
|
+
)
|
|
101
|
+
debug_config = {}
|
|
88
102
|
|
|
89
103
|
for component, loggers in _COMPONENT_LOGGERS.items():
|
|
90
104
|
component_config = debug_config.get(component)
|
|
@@ -105,8 +119,15 @@ def configure_component_debug_logging():
|
|
|
105
119
|
# Invalid config, fall back to DEBUG
|
|
106
120
|
log_level = logging.DEBUG
|
|
107
121
|
|
|
122
|
+
# Configure all loggers for this component
|
|
108
123
|
for logger_name in loggers:
|
|
109
|
-
logging.getLogger(logger_name)
|
|
124
|
+
component_logger = logging.getLogger(logger_name)
|
|
125
|
+
component_logger.setLevel(log_level)
|
|
126
|
+
component_logger.propagate = False # Prevent duplicate logging
|
|
127
|
+
# Attach main handlers to the component logger
|
|
128
|
+
for handler in main_handlers:
|
|
129
|
+
if handler not in component_logger.handlers:
|
|
130
|
+
component_logger.addHandler(handler)
|
|
110
131
|
else:
|
|
111
132
|
# Component debug is disabled - completely suppress external library logging
|
|
112
133
|
# Use a level higher than CRITICAL to effectively disable all messages
|
|
@@ -73,9 +73,18 @@ def print_banner():
|
|
|
73
73
|
|
|
74
74
|
async def main(config):
|
|
75
75
|
"""
|
|
76
|
-
|
|
76
|
+
Coordinate the asynchronous relay loop between Meshtastic and Matrix clients.
|
|
77
77
|
|
|
78
|
-
Initializes the database
|
|
78
|
+
Initializes the database and plugins, starts the message queue, connects to Meshtastic and Matrix, joins configured Matrix rooms, registers event callbacks, monitors connection health, runs the Matrix sync loop with automatic retries, and ensures an orderly shutdown of all components (including optional message map wiping on startup and shutdown).
|
|
79
|
+
|
|
80
|
+
Parameters:
|
|
81
|
+
config (dict): Application configuration mapping. Expected keys used by this function include:
|
|
82
|
+
- "matrix_rooms": list of room dicts with at least an "id" entry,
|
|
83
|
+
- "meshtastic": optional dict with "message_delay",
|
|
84
|
+
- "database" (preferred) or legacy "db": optional dict containing "msg_map" with "wipe_on_restart" boolean.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
ConnectionError: If connecting to Matrix fails and no Matrix client can be obtained.
|
|
79
88
|
"""
|
|
80
89
|
# Extract Matrix configuration
|
|
81
90
|
from typing import List
|
|
@@ -154,9 +163,9 @@ async def main(config):
|
|
|
154
163
|
|
|
155
164
|
async def shutdown():
|
|
156
165
|
"""
|
|
157
|
-
Signal the application to
|
|
158
|
-
|
|
159
|
-
|
|
166
|
+
Signal the application to begin shutdown.
|
|
167
|
+
|
|
168
|
+
Set the Meshtastic shutdown flag and set the local shutdown event so any coroutines waiting on that event can start cleanup.
|
|
160
169
|
"""
|
|
161
170
|
matrix_logger.info("Shutdown signal received. Closing down...")
|
|
162
171
|
meshtastic_utils.shutting_down = True # Set the shutting_down flag
|