Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: on_called_api 后处理异常的逻辑问题 #2373

Closed
Ailitonia opened this issue Sep 24, 2023 · 0 comments · Fixed by #2374
Closed

Bug: on_called_api 后处理异常的逻辑问题 #2373

Ailitonia opened this issue Sep 24, 2023 · 0 comments · Fixed by #2374
Labels
bug Something isn't working

Comments

@Ailitonia
Copy link
Contributor

操作系统

Windows

Python 版本

3.10.11

NoneBot 版本

2.1.0

适配器

adapter-qqguild 0.3.0

协议端

QQ-Guild

描述问题

这应该是一个 on_called_api 处理逻辑的问题

场景

adapter-qqguild 中发送图片之类的消息会引发审核异常 AuditException
为使插件层面不受该异常影响而通过 on_called_api 处理审核事件:

from typing import Any, Dict, Optional

from nonebot.exception import MockApiException
from nonebot.adapters.qqguild.bot import Bot as QQGuildBot
from nonebot.adapters.qqguild.exception import AuditException
from nonebot.adapters.qqguild.event import MessageAuditPassEvent, MessageAuditRejectEvent


@QQGuildBot.on_called_api
async def handle_api_result(
        bot: QQGuildBot,
        exception: Optional[Exception],
        api: str,
        data: Dict[str, Any],
        result: Any
):
    """获取消息发送后审核状态并自动处理 AuditException 事件"""
    if not isinstance(bot, QQGuildBot):
        return

    if exception is None:
        return

    if isinstance(exception, AuditException) and api == 'post_messages':
        audit_result = await exception.get_audit_result(timeout=30)
        
        if isinstance(audit_result, MessageAuditPassEvent):
            raise MockApiException(result=...)
        elif isinstance(audit_result, MessageAuditRejectEvent):
            raise exception
        else:
           ...

预期是能拦截 AuditException 并直接返回审核通过后的发送消息返回内容
实际上即使在 on_called_api 中抛出 MockApiExceptionbot.call_api 仍然抛出了 AuditException
原因是在第 108 行捕获 MockApiException 后仅修改了返回的 result 值, 对 exception 并未作处理, 然后 120 行直接抛出了 adapter._call_api 中的异常

if not skip_calling_api:
try:
result = await self.adapter._call_api(self, api, **data)
except Exception as e:
exception = e
if coros := [
hook(self, exception, api, data, result) for hook in self._called_api_hook
]:
try:
logger.debug("Running CalledAPI hooks...")
await asyncio.gather(*coros)
except MockApiException as e:
result = e.result
logger.debug(
f"Calling API {api} result is mocked. Return {result} instead."
)
except Exception as e:
logger.opt(colors=True, exception=e).error(
"<r><bg #f8bbd0>Error when running CalledAPI hook. "
"Running cancelled!</bg #f8bbd0></r>"
)
if exception:
raise exception
return result

在 api calling hook 中, MockApiException 应当明确表示阻止本次 API 调用或修改本次调用返回值, 并返回自定义内容, 上述场景中即使在 on_called_api 中抛出 MockApiException 后却仍然继续抛出原异常是不符直觉和逻辑的

复现步骤

期望的结果

No response

截图或日志

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

Successfully merging a pull request may close this issue.

1 participant