early response to the request
This commit is contained in:
+18
-4
@@ -38,6 +38,12 @@ _CALLBACK_ANSWER_IGNORE = (
|
||||
"query id is invalid",
|
||||
)
|
||||
|
||||
_MESSAGE_NOT_MODIFIED = "message is not modified"
|
||||
|
||||
|
||||
def _is_message_not_modified(exc: BaseException) -> bool:
|
||||
return isinstance(exc, TelegramBadRequest) and _MESSAGE_NOT_MODIFIED in str(exc).lower()
|
||||
|
||||
|
||||
async def safe_answer_callback(callback_query: CallbackQuery, text: str | None = None, show_alert: bool = False, **kwargs) -> None:
|
||||
"""
|
||||
@@ -298,7 +304,9 @@ async def edit_or_send_message(
|
||||
InputMediaAnimation(media=cached_id, caption=text), reply_markup=reply_markup
|
||||
)
|
||||
return
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
if _is_message_not_modified(e):
|
||||
return
|
||||
try:
|
||||
if media_type == "photo":
|
||||
await target_message.answer_photo(
|
||||
@@ -342,7 +350,9 @@ async def edit_or_send_message(
|
||||
msg = await target_message.edit_media(
|
||||
InputMediaAnimation(media=upload, caption=text), reply_markup=reply_markup
|
||||
)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
if _is_message_not_modified(e):
|
||||
return
|
||||
if media_type == "photo":
|
||||
msg = await target_message.answer_photo(
|
||||
photo=upload,
|
||||
@@ -385,7 +395,9 @@ async def edit_or_send_message(
|
||||
try:
|
||||
await target_message.edit_caption(caption=text, reply_markup=reply_markup)
|
||||
return
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
if _is_message_not_modified(e):
|
||||
return
|
||||
pass
|
||||
try:
|
||||
await target_message.edit_text(
|
||||
@@ -394,7 +406,9 @@ async def edit_or_send_message(
|
||||
disable_web_page_preview=disable_web_page_preview,
|
||||
)
|
||||
return
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
if _is_message_not_modified(e):
|
||||
return
|
||||
await target_message.answer(
|
||||
text=text,
|
||||
reply_markup=reply_markup,
|
||||
|
||||
@@ -7,7 +7,7 @@ from middlewares.ban_checker import BanCheckerMiddleware
|
||||
from middlewares.subscription import SubscriptionMiddleware
|
||||
|
||||
from .admin import AdminMiddleware
|
||||
from .answer import CallbackAnswerMiddleware
|
||||
from .answer import CallbackAnswerMiddleware, EarlyCallbackAnswerMiddleware
|
||||
from .concurrency import ConcurrencyLimiterMiddleware
|
||||
from .direct_start_blocker import DirectStartBlockerMiddleware
|
||||
from .loggings import LoggingMiddleware
|
||||
@@ -60,6 +60,9 @@ def register_middleware(
|
||||
if PROBE_LOGGING:
|
||||
dispatcher.update.outer_middleware(StreamProbeMiddleware("global"))
|
||||
|
||||
# Первым делом отвечаем на callback, чтобы не уйти в «query is too old» при очереди
|
||||
dispatcher.update.outer_middleware(EarlyCallbackAnswerMiddleware())
|
||||
|
||||
if middleware_enabled("runtime_config_sync"):
|
||||
dispatcher.update.outer_middleware(wrap(RuntimeConfigSyncMiddleware(), "runtime_config_sync"))
|
||||
if sessionmaker and middleware_enabled("concurrency"):
|
||||
|
||||
+36
-2
@@ -1,12 +1,46 @@
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import Any
|
||||
|
||||
from aiogram import BaseMiddleware
|
||||
from aiogram import BaseMiddleware, Bot
|
||||
from aiogram.exceptions import TelegramBadRequest
|
||||
from aiogram.types import CallbackQuery, InaccessibleMessage, TelegramObject
|
||||
|
||||
from bot import bot
|
||||
|
||||
|
||||
class EarlyCallbackAnswerMiddleware(BaseMiddleware):
|
||||
"""
|
||||
Регистрируется первым в цепочке update. Для CallbackQuery сразу вызывает
|
||||
answer_callback_query.
|
||||
"""
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
|
||||
event: TelegramObject,
|
||||
data: dict[str, Any],
|
||||
) -> Any:
|
||||
if isinstance(event, CallbackQuery):
|
||||
bot_instance: Bot | None = data.get("bot")
|
||||
if bot_instance:
|
||||
try:
|
||||
await bot_instance.answer_callback_query(event.id, show_alert=False)
|
||||
data["callback_answered_early"] = True
|
||||
except TelegramBadRequest as e:
|
||||
msg = str(e).lower()
|
||||
if (
|
||||
"query is too old" in msg
|
||||
or "response timeout expired" in msg
|
||||
or "query id is invalid" in msg
|
||||
):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
except Exception:
|
||||
pass
|
||||
return await handler(event, data)
|
||||
|
||||
|
||||
class CallbackAnswerMiddleware(BaseMiddleware):
|
||||
async def __call__(
|
||||
self,
|
||||
@@ -14,7 +48,7 @@ class CallbackAnswerMiddleware(BaseMiddleware):
|
||||
event: TelegramObject,
|
||||
data: dict[str, Any],
|
||||
) -> Any:
|
||||
if isinstance(event, CallbackQuery) and not data.get("callback_answered_by_concurrency"):
|
||||
if isinstance(event, CallbackQuery) and not data.get("callback_answered_by_concurrency") and not data.get("callback_answered_early"):
|
||||
try:
|
||||
await event.answer()
|
||||
except Exception:
|
||||
|
||||
@@ -33,7 +33,7 @@ class ConcurrencyLimiterMiddleware(BaseMiddleware):
|
||||
event: TelegramObject,
|
||||
data: dict[str, Any],
|
||||
) -> Any:
|
||||
if isinstance(event, CallbackQuery):
|
||||
if isinstance(event, CallbackQuery) and not data.get("callback_answered_early"):
|
||||
bot: Bot | None = data.get("bot")
|
||||
if bot:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user