fix: push the final text into the draft before sending it as a message
Драфт с последней фразой висел в чате ещё несколько секунд после того, как
уже ушло сообщение «✅ Обучение завершено»: содержимое драфта не совпадало
с финальным сообщением, и клиент не мог их слить.
Финальный текст теперь сначала пушится в драфт тем же draft_id, и только
потом уходит реальным сообщением с тем же текстом — драфт заменяется без
задержки. finish() без текста гасит драфт пустым пушем.
Проверено: 198 тестов OK (2 новых на совпадение текста драфта и сообщения).
VERSION: 0.1.0+50 -> 0.1.0+51
This commit is contained in:
1 parent
635b78cb86
commit
7a630a974f
5 files changed
+69
-13
No files matched your search
@@ -896,18 +896,22 @@ class OperationStatus:
|
||||
async def finish(self, text: str | None = None) -> None:
|
||||
"""Close the status out.
|
||||
|
||||
A live draft only disappears once the bot sends a real message, so the
|
||||
final text must always go out through ``sendMessage`` — otherwise the
|
||||
last activity phrase keeps hanging in the chat for the rest of the
|
||||
draft's TTL.
|
||||
A live draft only disappears once the bot sends a real message. Its
|
||||
content must match that message, otherwise the client cannot merge
|
||||
them: the draft keeps floating in the chat for a few more seconds
|
||||
while already being stale. So the final text is pushed into the draft
|
||||
first, then sent as a real message with the same text.
|
||||
"""
|
||||
await self.cancel()
|
||||
self._closed = True
|
||||
if text is None:
|
||||
await self._clear_draft()
|
||||
return
|
||||
self._last_text = text
|
||||
if self.message is not None and self._finished_draft_id is not None:
|
||||
# Draft path: a real message replaces the draft in the chat.
|
||||
# Bring the draft to the final text so the real message replaces it
|
||||
# instead of racing a stale one.
|
||||
await self._push_draft(self._finished_draft_id, text)
|
||||
self.draft_id = None
|
||||
try:
|
||||
await self.message.answer(text)
|
||||
@@ -916,6 +920,26 @@ class OperationStatus:
|
||||
return
|
||||
await self.update(text)
|
||||
|
||||
async def _push_draft(self, draft_id: int, text: str) -> None:
|
||||
message = self.message
|
||||
if message is None or message.bot is None:
|
||||
return
|
||||
try:
|
||||
await message.bot.send_message_draft(
|
||||
chat_id=message.chat.id,
|
||||
draft_id=draft_id,
|
||||
text=text,
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.debug("Draft push failed (%s): %s", type(exc).__name__, str(exc)[:120])
|
||||
|
||||
async def _clear_draft(self) -> None:
|
||||
"""Drop the draft without leaving any text behind."""
|
||||
draft_id = self._finished_draft_id
|
||||
if draft_id is None:
|
||||
return
|
||||
await self._push_draft(draft_id, "")
|
||||
|
||||
async def finish_if_open(self, text: str) -> None:
|
||||
"""Safety net: close the status only if nothing has closed it yet."""
|
||||
if not self._closed:
|
||||
|
||||
Reference in new issue
Block a user