This commit introduces asynchronous handling for response formatting in the command manager, allowing network-backed filters to resolve off-thread without blocking the event loop. Key changes include:
- Added `check_keywords_async` method to `CommandManager` to handle keyword checks asynchronously.
- Updated `TestCommand` and `PathCommand` to utilize the new async formatting capabilities.
- Enhanced `response_template` with `format_piped_template_async` for improved performance during template rendering.
- Updated documentation to reflect support for async response formatting in both `path`'s `reply_prefix` and the test command's `response_format`.
This change improves responsiveness and reduces potential delays caused by synchronous network calls during message processing.
Adds the 16-char MeshCore packet identity hash to the three formatters that
render user-facing templates: [Keywords] responses, the test command's
response_format, and the path command's reply_prefix. It is read only from
routing_info, which is attached solely from an RF packet correlated to the
message, so a hash from an unrelated transmission is never shown. Missing,
empty, and the 0000000000000000 error sentinel all render empty.
get_packet_hash_placeholder returns "" rather than a False sentinel. Empty
gives byte-identical output on every path—prefix_if_nonempty already tests
falsiness and str.format renders "" as nothing—whereas False would print
the literal string "False" into a mesh reply from any consumer of
get_standard_placeholder_fields that formatted it directly.
TestCommand.format_response now builds on get_standard_placeholder_fields
instead of duplicating it. That also honors the extra argument its docstring
already promised but silently ignored, and picks up the path-string hop
fallback, so {hops} reads "0" rather than "?" for a message whose hops and
routing_info are both unset but whose path says "Direct (0 hops)".
Documents the placeholder in config.ini.example, the default config that
core.py writes on a fresh install, the README and docs/path-command-config.md.
The generated config was also missing {elapsed}; added that too.
Keep the disabled-command fallback in one place. A disabled command still
matches; can_execute is what holds it back, and the dispatcher continues past it
so another command's alias can claim the trigger. The per-command enabled guards
in matches_keyword were a second mechanism for a problem already solved once, and
one every command would have to repeat, so drop them along with PathCommand's
matches_keyword override entirely.
Restore control-character tolerance in the test command. Matching runs against
clean_content-normalized text again, so a garbled "test" still matches. A test is
exactly the message someone sends when their link is marginal. The cleaned text
only sticks when the test command claims the message, since matching runs early
in the command scan and collapsing whitespace on another command's free-form
argument is not its business.
Make enable_p_shortcut = false actually work. Appending "p" to the inherited
class list left it on PathCommand.keywords for every instance built afterwards,
so a reload with the shortcut off still answered "p".
Have split_trigger_and_args honour the configured command prefix instead of
stripping a leading "!" unconditionally, and match word by word rather than
slicing the lowered copy by keyword length, which cuts the args in the wrong
place when str.lower() changes length for a non-ASCII alias.
Mention gating now applies to the test command, which the bespoke matcher had
skipped: "test @[Bob]" in a channel no longer gets an ack.
Removed redundant logging for command execution and added detailed debug logging for cases where a command cannot execute due to soft rejections. This allows for better tracking of command flow and ensures that keyword matching continues for subsequent commands. Updated the test_command to include config aliases in keyword matching, enhancing its flexibility.
Total path distance was already a solved problem here: the test command
computes it and exposes {path_distance} through the piped-template
engine, with pipe filters and docs. The path command just had no way to
reach it, since reply_prefix went through plain str.format.
Rather than add a second distance implementation, this reuses what
exists. BaseCommand.get_standard_placeholder_fields now returns the
shared placeholder set so subclasses can extend it, the path command
renders reply_prefix through format_piped_template with an added
{path_distance}, and the sum itself uses utils.calculate_distance over
the nodes the path command has already resolved.
Distance covers sender -> each hop -> bot and is deliberately blank when
the chain cannot be measured end to end (unresolved hop, prefix
collision, missing or 0,0 coordinates, unknown sender, no configured
bot position), so a partial sum is never reported as the real distance.
Because the prefix now supports pipe filters, an empty value takes its
label with it: {path_distance|prefix_if_nonempty:📏 }
Supersedes #198, which added a parallel haversine, a show_path_distance
flag, and a distance_traveled key across 10 locales.
- Enhanced the `TestCommand` class to include the `rssi` value in the response format, allowing for more detailed output.
- Updated the example configuration to reflect the new placeholder usage for `rssi`.
- Added a unit test to verify that the `rssi` placeholder expands correctly in the response message.
- Added configuration options to specify minimum path byte length requirements for the path, test, and multitest commands.
- Introduced methods to enforce these requirements and handle failure responses.
- Updated the packet capture service to correctly calculate packet hashes using the raw wire byte length.
- Enhanced unit tests to verify the correct behavior of the new path byte length logic.
- Updated `config.ini.example` to clarify flood scope configuration, introducing the auto-hashtag format for region names and adding support for multi-scope replies.
- Refactored `ChannelManager` to improve handling of empty channels, adjusting timeout logic and increasing request delay to prevent overwhelming devices.
- Enhanced `CommandManager` to load flood scope keys for HMAC matching and normalize scope names for consistency.
- Implemented scope matching in `MessageHandler` to ensure replies respect configured flood scopes, improving message routing accuracy.
- Updated `MeshMessage` model to include a `reply_scope` attribute for tracking matched flood scopes.
- Introduced `extract_path_node_ids_from_message` to streamline extraction of node IDs from mesh messages, prioritizing `routing_info.path_nodes` and supporting multi-byte comma parsing.
- Updated `calculate_path_distances` to accept an optional message parameter, enhancing its functionality by allowing it to derive node IDs from messages.
- Added `node_ids_from_path_string` to handle parsing of path strings into node IDs, improving the handling of both legacy and multi-byte formats.
- Refactored `TestCommand` to utilize the new extraction function, ensuring consistent behavior across commands.
- Expanded test coverage for new utility functions to validate their correctness and robustness.
These changes improve the clarity and maintainability of path-related utilities, enhancing overall functionality in message processing.
BUG-001: web viewer login/session auth (in web viewer commit)
BUG-002: db_manager ALTER TABLE for missing channel_operations and
feed_message_queue columns on startup
BUG-015: scheduler thread blocked on future.result(); replaced all
blocking waits with add_done_callback (fire-and-forget)
BUG-016: reboot_radio sends meshcore.commands.reboot() before disconnect
BUG-017: radio disconnect uses asyncio.wait_for(timeout=10)
BUG-022: custom asyncio loop exception handler suppresses IndexError
from meshcore parser at DEBUG level
BUG-024: last_db_backup_run updated after each run; 2-min startup
window; last-run seeded from DB on restart
BUG-025: send_channel_message retries up to 2 times (2s delay) on
no_event_received via _is_no_event_received() helper
BUG-026: split_text_into_chunks() and get_max_message_length() added
to CommandManager; keyword dispatch uses send_response_chunked()
BUG-028: byte_data = b"" initialised before try block in
decode_meshcore_packet to prevent UnboundLocalError in except handler
TraceCommand: path nodes reversed and return path truncated; fixed
format_elapsed_display: UTC normalisation before elapsed computation (#75)
RepeaterManager: auto_manage_contacts guard before any purge logic (#50)
Command aliases: [Aliases] config section injects shorthands at startup
JSON logging: _JsonFormatter; json_logging = true in [Logging]
Structured JSON logging compatible with Loki, Elasticsearch, Splunk
Discord bridge, Telegram bridge, and all service plugins updated
MeshGraph edge promotion logic corrected
Shutdown: scheduler and meshcore disconnect joined cleanly; log spam fixed
All modules: ruff and mypy cleanup applied (type annotations, imports)
- Updated `meshcore` dependency version to `2.2.14` in both `pyproject.toml` and `requirements.txt`.
- Added multi-byte path support in the `PathCommand`, allowing for 1-, 2-, and 3-byte-per-hop paths.
- Enhanced `MessageHandler` to utilize `routing_info` for accurate path extraction and validation.
- Improved path extraction methods in `MultitestCommand` and `TestCommand` to prefer `routing_info` for node IDs.
- Refactored path handling logic across various commands to ensure consistent multi-byte path processing.
- Updated the `generate_html` function to include detailed command usage information, including syntax, examples, and parameters for better user guidance.
- Added CSS styles for improved presentation of command usage and parameters in the generated website documentation.
- Enhanced command classes with structured documentation fields, allowing for consistent and informative command descriptions across the platform.
- Implemented a configuration option for enabling or disabling commands across multiple command classes.
- Each command now checks its enabled state before execution, improving control over command availability.
- Updated the configuration loading mechanism to retrieve the enabled state from the config file for commands like Advert, AQI, Catfact, and others.
- Updated the test command response format to include optional phrases.
- Removed the at_phrase command and its references from the command manager and help command.
- Adjusted configuration examples to reflect the new syntax for message acknowledgments.
- Enhanced the sports command with additional WNBA team support and improved city mappings for team searches.