mirror of
				https://github.com/nonebot/nonebot2.git
				synced 2025-11-03 16:36:44 +00:00 
			
		
		
		
	🚸 add support of rule to_me in mirai adapter
				
					
				
			This commit is contained in:
		@@ -13,11 +13,12 @@ from nonebot.exception import ApiNotAvailable, RequestDenied
 | 
			
		||||
from nonebot.log import logger
 | 
			
		||||
from nonebot.message import handle_event
 | 
			
		||||
from nonebot.typing import overrides
 | 
			
		||||
from nonebot.utils import escape_tag
 | 
			
		||||
 | 
			
		||||
from .config import Config as MiraiConfig
 | 
			
		||||
from .event import Event, FriendMessage, GroupMessage, TempMessage
 | 
			
		||||
from .message import MessageChain, MessageSegment
 | 
			
		||||
from .utils import catch_network_error, argument_validation
 | 
			
		||||
from .utils import catch_network_error, argument_validation, check_tome, Log
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionManager:
 | 
			
		||||
@@ -209,11 +210,22 @@ class Bot(BaseBot):
 | 
			
		||||
 | 
			
		||||
    @overrides(BaseBot)
 | 
			
		||||
    async def handle_message(self, message: dict):
 | 
			
		||||
        await handle_event(bot=self,
 | 
			
		||||
                           event=Event.new({
 | 
			
		||||
                               **message,
 | 
			
		||||
                               'self_id': self.self_id,
 | 
			
		||||
                           }))
 | 
			
		||||
        Log.debug(f'received message {message}')
 | 
			
		||||
        try:
 | 
			
		||||
            await handle_event(
 | 
			
		||||
                bot=self,
 | 
			
		||||
                event=await check_tome(
 | 
			
		||||
                    bot=self,
 | 
			
		||||
                    event=Event.new({
 | 
			
		||||
                        **message,
 | 
			
		||||
                        'self_id': self.self_id,
 | 
			
		||||
                    }),
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            logger.opt(colors=True, exception=e).exception(
 | 
			
		||||
                'Failed to handle message '
 | 
			
		||||
                f'<r>{escape_tag(str(message))}</r>: ')
 | 
			
		||||
 | 
			
		||||
    @overrides(BaseBot)
 | 
			
		||||
    async def call_api(self, api: str, **data) -> NoReturn:
 | 
			
		||||
 
 | 
			
		||||
@@ -80,8 +80,8 @@ class Event(BaseEvent):
 | 
			
		||||
                return event_class.parse_obj(data)
 | 
			
		||||
            except ValidationError as e:
 | 
			
		||||
                logger.info(
 | 
			
		||||
                    f'Failed to parse {data} to class {event_class.__name__}: {e}. '
 | 
			
		||||
                    'Fallback to parent class.')
 | 
			
		||||
                    f'Failed to parse {data} to class {event_class.__name__}: '
 | 
			
		||||
                    f'{e.errors()!r}. Fallback to parent class.')
 | 
			
		||||
                event_class = event_class.__base__
 | 
			
		||||
 | 
			
		||||
        raise ValueError(f'Failed to serialize {data}.')
 | 
			
		||||
 
 | 
			
		||||
@@ -33,11 +33,20 @@ class MessageEvent(Event):
 | 
			
		||||
class GroupMessage(MessageEvent):
 | 
			
		||||
    """群消息事件"""
 | 
			
		||||
    sender: GroupChatInfo
 | 
			
		||||
    to_me: bool = False
 | 
			
		||||
 | 
			
		||||
    @overrides(MessageEvent)
 | 
			
		||||
    def get_session_id(self) -> str:
 | 
			
		||||
        return f'group_{self.sender.group.id}_' + self.get_user_id()
 | 
			
		||||
 | 
			
		||||
    @overrides(MessageEvent)
 | 
			
		||||
    def get_user_id(self) -> str:
 | 
			
		||||
        return str(self.sender.id)
 | 
			
		||||
 | 
			
		||||
    @overrides(MessageEvent)
 | 
			
		||||
    def is_tome(self) -> bool:
 | 
			
		||||
        return self.to_me
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FriendMessage(MessageEvent):
 | 
			
		||||
    """好友消息事件"""
 | 
			
		||||
@@ -47,15 +56,23 @@ class FriendMessage(MessageEvent):
 | 
			
		||||
    def get_user_id(self) -> str:
 | 
			
		||||
        return str(self.sender.id)
 | 
			
		||||
 | 
			
		||||
    @overrides
 | 
			
		||||
    @overrides(MessageEvent)
 | 
			
		||||
    def get_session_id(self) -> str:
 | 
			
		||||
        return 'friend_' + self.get_user_id()
 | 
			
		||||
 | 
			
		||||
    @overrides(MessageEvent)
 | 
			
		||||
    def is_tome(self) -> bool:
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TempMessage(MessageEvent):
 | 
			
		||||
    """临时会话消息事件"""
 | 
			
		||||
    sender: GroupChatInfo
 | 
			
		||||
 | 
			
		||||
    @overrides
 | 
			
		||||
    @overrides(MessageEvent)
 | 
			
		||||
    def get_session_id(self) -> str:
 | 
			
		||||
        return f'temp_{self.sender.group.id}_' + self.get_user_id()
 | 
			
		||||
 | 
			
		||||
    @overrides(MessageEvent)
 | 
			
		||||
    def is_tome(self) -> bool:
 | 
			
		||||
        return True
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,44 @@
 | 
			
		||||
import re
 | 
			
		||||
from functools import wraps
 | 
			
		||||
from typing import Callable, Coroutine, TypeVar
 | 
			
		||||
from typing import TYPE_CHECKING, Any, Callable, Coroutine, Optional, TypeVar
 | 
			
		||||
 | 
			
		||||
import httpx
 | 
			
		||||
from pydantic import ValidationError, validate_arguments, Extra
 | 
			
		||||
from pydantic import Extra, ValidationError, validate_arguments
 | 
			
		||||
 | 
			
		||||
import nonebot.exception as exception
 | 
			
		||||
from nonebot.log import logger
 | 
			
		||||
from nonebot.utils import escape_tag
 | 
			
		||||
from nonebot.utils import escape_tag, logger_wrapper
 | 
			
		||||
 | 
			
		||||
from .event import Event, GroupMessage
 | 
			
		||||
from .message import MessageSegment, MessageType
 | 
			
		||||
 | 
			
		||||
if TYPE_CHECKING:
 | 
			
		||||
    from .bot import Bot
 | 
			
		||||
 | 
			
		||||
_AsyncCallable = TypeVar("_AsyncCallable", bound=Callable[..., Coroutine])
 | 
			
		||||
_AnyCallable = TypeVar("_AnyCallable", bound=Callable)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Log:
 | 
			
		||||
    _log = logger_wrapper('MIRAI')
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def info(cls, message: Any):
 | 
			
		||||
        cls._log('INFO', str(message))
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def debug(cls, message: Any):
 | 
			
		||||
        cls._log('DEBUG', str(message))
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def warn(cls, message: Any):
 | 
			
		||||
        cls._log('WARNING', str(message))
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def error(cls, message: Any, exception: Optional[Exception] = None):
 | 
			
		||||
        cls._log('ERROR', str(message), exception=exception)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActionFailed(exception.ActionFailed):
 | 
			
		||||
    """
 | 
			
		||||
    :说明:
 | 
			
		||||
@@ -89,3 +116,41 @@ def argument_validation(function: _AnyCallable) -> _AnyCallable:
 | 
			
		||||
            raise InvalidArgument
 | 
			
		||||
 | 
			
		||||
    return wrapper  # type: ignore
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def check_tome(bot: "Bot", event: "Event") -> "Event":
 | 
			
		||||
    if not isinstance(event, GroupMessage):
 | 
			
		||||
        return event
 | 
			
		||||
 | 
			
		||||
    def _is_at(event: GroupMessage) -> bool:
 | 
			
		||||
        for segment in event.message_chain:
 | 
			
		||||
            segment: MessageSegment
 | 
			
		||||
            if segment.type != MessageType.AT:
 | 
			
		||||
                continue
 | 
			
		||||
            if segment.data['target'] == event.self_id:
 | 
			
		||||
                return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def _is_nick(event: GroupMessage) -> bool:
 | 
			
		||||
        text = event.get_plaintext()
 | 
			
		||||
        if not text:
 | 
			
		||||
            return False
 | 
			
		||||
        nick_regex = '|'.join(
 | 
			
		||||
            {i.strip() for i in bot.config.nickname if i.strip()})
 | 
			
		||||
        matched = re.search(rf"^({nick_regex})([\s,,]*|$)", text, re.IGNORECASE)
 | 
			
		||||
        if matched is None:
 | 
			
		||||
            return False
 | 
			
		||||
        Log.info(f'User is calling me {matched.group(1)}')
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def _is_reply(event: GroupMessage) -> bool:
 | 
			
		||||
        for segment in event.message_chain:
 | 
			
		||||
            segment: MessageSegment
 | 
			
		||||
            if segment.type != MessageType.QUOTE:
 | 
			
		||||
                continue
 | 
			
		||||
            if segment.data['senderId'] == event.self_id:
 | 
			
		||||
                return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    event.to_me = any([_is_at(event), _is_reply(event), _is_nick(event)])
 | 
			
		||||
    return event
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user