mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-10-23 22:32:29 +00:00
fix(response_template,url_shortener): follow-ups to PR #254
Integration fixes on top of the merge, in three groups. Regressions in the shared shortener, which is not opt-in — weather alerts call it unconditionally whenever an alert carries a link: - Restore the `response.ok` guard on the v.gd path. Without it a 503 whose body happens to start with `http` (a captive portal, a CDN error page) was returned as the short URL. The test that covered this still passed because it never set `.text`, so `MagicMock.startswith()` answered truthily; it now supplies a body that would be accepted on a 200, so only the status check can make it pass. - Add the same guard to the shlink path, where a rejected API key is a 401 with a problem-details body and was indistinguishable from an empty result. - Restore debug-level logging for `Timeout`/`ConnectionError`. A mesh node's uplink drops out routinely and this had become `logger.error`. - Drop the `shortUrlSlug` fallback. Shlink's create response carries `shortUrl` and `shortCode`; `shortUrlSlug` is not in its schema, and a bare slug is not a link — emitting one would have put `abc123` in a message. The `shorten_url` filter did blocking HTTP inside the synchronous render path (`process_message` → `check_keywords` → `format_response`), so a 5 s shortener timeout stalled the radio transport along with everything else. Making `check_keywords` async would touch 27 call sites, so instead the network work moves ahead of the render: - `resolve_template_async()` renders once with the filter in collection mode, which walks the real chain so a clause already suppressed by `hops_min` costs no request, then shortens what survived concurrently off-thread. - The filter itself now only reads that mapping and never calls out. Asked to render without a pre-pass it warns and drops the clause rather than block. - On failure the clause is dropped rather than sent unshortened. A v.gd link is ~19 bytes where the analyzer URL is ~59, against a ~158-byte budget the prefix is subtracted from, so falling back would have turned one transmission into two whenever the shortener was unreachable. Smaller: rename `if_notempty` to `if_nonempty` to match the existing `prefix_if_nonempty` (nothing ships using it yet, so there is no config to migrate); `_build_create_shlink_url` no longer takes the long URL and API key it never used; move the CHANGELOG entry from Fixed to Added and name the filter it actually added; ungate the render debug log from `config`; document that `shorten_url` is supported in `path`'s `reply_prefix` only. Every template shipped in config.ini.example still renders identically to the regex parser it replaced.
This commit is contained in:
1 parent
ec6b9cbfc0
commit
7fbfb07a85
8 files changed
+324
-62
No files matched your search
@@ -15,7 +15,7 @@ from ..path_inference import (
|
||||
select_node_repeater,
|
||||
select_repeater_by_graph,
|
||||
)
|
||||
from ..response_template import format_piped_template
|
||||
from ..response_template import format_piped_template, resolve_template_async
|
||||
from ..utils import (
|
||||
bytes_per_hop_from_routing_and_nodes,
|
||||
calculate_distance,
|
||||
@@ -415,18 +415,30 @@ class PathCommand(BaseCommand):
|
||||
return ''
|
||||
return f"{distance:.1f}km"
|
||||
|
||||
def _format_path_reply_prefix(self, message: MeshMessage) -> str:
|
||||
async def _format_path_reply_prefix(self, message: MeshMessage) -> str:
|
||||
if not self.path_reply_prefix:
|
||||
return ''
|
||||
fields = self.get_standard_placeholder_fields(message)
|
||||
fields['path_distance'] = self._format_path_distance(message)
|
||||
formatted = format_piped_template(
|
||||
str_fields = {k: str(v) for k, v in fields.items()}
|
||||
# Any URL shortening happens here, off the event loop, before the
|
||||
# synchronous render runs. See modules.response_template.
|
||||
shortened = await resolve_template_async(
|
||||
self.path_reply_prefix,
|
||||
{k: str(v) for k, v in fields.items()},
|
||||
str_fields,
|
||||
message=message,
|
||||
logger=self.logger,
|
||||
config=self.bot.config,
|
||||
prefix_hex_chars=getattr(self.bot, 'prefix_hex_chars', 2),
|
||||
)
|
||||
formatted = format_piped_template(
|
||||
self.path_reply_prefix,
|
||||
str_fields,
|
||||
message=message,
|
||||
logger=self.logger,
|
||||
config=self.bot.config,
|
||||
shortened=shortened,
|
||||
prefix_hex_chars=getattr(self.bot, 'prefix_hex_chars', 2),
|
||||
).rstrip()
|
||||
if not formatted:
|
||||
return ''
|
||||
@@ -1057,7 +1069,7 @@ class PathCommand(BaseCommand):
|
||||
|
||||
async def _send_path_response(self, message: MeshMessage, response: str):
|
||||
"""Send path response, splitting into multiple messages if necessary"""
|
||||
prefix = self._format_path_reply_prefix(message)
|
||||
prefix = await self._format_path_reply_prefix(message)
|
||||
self.last_response = prefix + response if prefix else response
|
||||
|
||||
max_length = self.get_max_message_length(message)
|
||||
|
||||
Reference in new issue
Block a user