Skip to content

Имя автора из MeshCore в Telegram (room-server + каналы) + экранирование HTML - #19

Merged
Flexlug merged 6 commits into
mainfrom
claude/telegram-transport
Jun 27, 2026
Merged

Имя автора из MeshCore в Telegram (room-server + каналы) + экранирование HTML#19
Flexlug merged 6 commits into
mainfrom
claude/telegram-transport

Conversation

@Flexlug

@Flexlug Flexlug commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Проблема

В Telegram не было видно имени ноды-автора сообщений из MeshCore (началось с room-server).

Корень (подтверждён реальным пейлоадом)

Имя автора в MeshCore доставляется по-разному, и мост это не учитывал:

  • Каналы (CHANNEL_MSG_RECV): поля автора в кадре нет вообще — имя едет в тексте как "Имя: текст".
  • Room server (CONTACT_MSG_RECV, txt_type=2): автор едет структурным полем signature = 4-байтовый префикс ключа автора (pubkey_prefix — это ключ КОМНАТЫ, не автора). Текст — чистый.

При этом meshcore_py RX-событие именем не обогащает, а telegram send() для LoRa-источников вообще ронял display_name.

Что сделано

  • room-server (70ac208): резолв signature → adv_name через встроенный mc.get_contact_by_key_prefix (+ кэш контактов свежим через ensure_contacts/auto_update_contacts), fallback на hex-префикс. Унифицирован telegram send(): bridge — как есть, каналы (пустой display_name) — passthrough, всё с именем — жирным префиксом.
  • каналы (105bcd9): split_author выносит "Имя: текст" в display_name. Ripple-фиксы (закрыты тестами): dedup-ключ получил display_name (у всех mesh-отправителей общий LORA_SENDER_UID), а LoRa↔LoRa relay восстанавливает автора в echo-safe скобочном формате [ник] текст.
  • HTML-экранирование (bd25023): send() ставил parse_mode=HTML безусловно без экранирования — любой </& из эфира ронял отправку. Теперь html.escape в bold-ветке, plain без parse_mode в passthrough.
  • docs/rules (d831557, bfb6695): принцип «фреймворк-first» + актуализация §12.1.

Проверка

  • 275 тестов зелёные, ruff чист, mypy без новых ошибок (15 — baseline).
  • End-to-end на реальном железе: имя автора видно и для канала, и для room-server.

🤖 Generated with Claude Code

Flexlug and others added 6 commits June 28, 2026 01:10
Перед проектированием граничного решения сперва ресёрч того, что уже умеет
библиотека (её функции/кэши/события), и только если фреймворк — слабое место,
лезть в протокол. Слабые места фиксировать явно. Дистиллировано из разбора
room-server атрибуции автора: резолв оказался встроенным (get_contact_by_key_prefix
+ ensure_contacts), а не поводом писать свой стор.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Room-server CONTACT_MSG_RECV несёт автора структурным полем signature
(4-байтовый префикс ключа автора), а не в тексте, как каналы. Подтверждено
реальным пейлоадом: txt_type=2, signature присутствует, text чистый.

Было: display_name = pubkey_prefix КОМНАТЫ (не автор), и telegram send() ронял
display_name для LoRa -> имени автора в Telegram не видно.

Стало:
- transport держит кэш контактов фреймворка свежим (auto_update_contacts +
  ensure_contacts) и прокидывает резолвер автора (get_contact_by_key_prefix) в
  RX-путь через route_rx/try_rx;
- room_server_to_message резолвит signature -> adv_name, fallback на hex-префикс;
- telegram send() унифицирован: bridge — как есть, каналы (пустой display_name) —
  passthrough, всё с именем (TG-юзер ИЛИ room-server автор) — жирным префиксом.

Каналы пока без изменений (имя у них в тексте) — унификация display_name для
каналов отдельным коммитом (задевает LoRa->LoRa relay).

Closes LoRa-Bridge-fhb

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Каналы несут автора в тексте как 'Имя: текст' (отдельного поля в
CHANNEL_MSG_RECV нет). Выносим его в sender.display_name, как у room-server,
чтобы Telegram рисовал автора единообразно (жирным).

channel_util.split_author режет по ПЕРВОМУ ': '; channel_to_message кладёт имя
в display_name, тело чистит.

Ripple-эффекты переноса автора из text в display_name (важно — закрыты тестами):
- dedup: ключ был transport_uid+text, но у всех mesh-отправителей transport_uid
  одинаков (LORA_SENDER_UID) — имя в тексте было единственным различителем.
  Добавили display_name в ключ, иначе разные авторы с одинаковым телом
  схлопывались бы в дубль.
- relay (LoRa->LoRa): форвардил src.text как есть, что теперь потеряло бы автора.
  transform.relay_lora_text восстанавливает его как '[ник] текст' — скобки, а не
  'ник: текст', чтобы обратный split_author не распарсил и loop-guard эха не
  сломался (закреплено cross-module тестом echo-safety).

Closes LoRa-Bridge-06q

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Контракт relay изменился вместе с переносом автора из text в display_name:
relay восстанавливает '[ник] текст' (relay_lora_text), а не форвардит как есть.
Старый текст про «без ре-префикса» устарел.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
send() ставил parse_mode=HTML безусловно и интерполировал display_name и
msg.text без экранирования — любой <, & или незакрытый тег из эфира/чата ронял
send_message (HTML-парсер Telegram), и сообщение терялось.

- bold-ветка: html.escape() на имя и тело;
- passthrough-ветка (bridge/каналы): без parse_mode (plain) — тело не
  интерпретируется как HTML.

HTML оставлен осознанно: escape-набор минимален (<>&, есть html.escape),
MarkdownV2 потребовал бы экранировать ~18 символов в каждом теле.

Closes LoRa-Bridge-ozt

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ensure_contacts подтверждён на железе (имя автора room-server и канала видно в
Telegram). Тестовые config.room.yaml / config.channel.yaml — в .gitignore
(реальные chat id / pubkey / secret).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Flexlug
Flexlug merged commit 86b22ee into main Jun 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant