diff --git a/README.md b/README.md index 8ae7949..1f4f06d 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,5 @@ pip install kuriyama ### 许可证 我们使用 [`GNU AGPLv3`](https://choosealicense.com/licenses/agpl-3.0/) 作为本项目的开源许可证, 而由于原项目 [`mirai`](https://github.com/mamoe/mirai) 同样使用了 `GNU AGPLv3` 作为开源许可证, 因此你在使用时需要遵守相应的规则. + +依赖注入思路: 检查run_body是否定义注入 => 传入上下文系统并执行注入 => 获取返回值并设置. \ No newline at end of file diff --git a/mirai/__init__.py b/mirai/__init__.py index 08bc032..1bc1fff 100644 --- a/mirai/__init__.py +++ b/mirai/__init__.py @@ -38,7 +38,7 @@ ExternalEvents ) from mirai.event.builtins import ( - UnexceptedException + UnexpectedException ) from mirai.event.external import ( BotOnlineEvent, diff --git a/mirai/command.py b/mirai/command.py index 8c8b8c1..f8cb3a1 100644 --- a/mirai/command.py +++ b/mirai/command.py @@ -1,16 +1,30 @@ from .session import Session +from . import ( + MessageChain, + Plain +) class Command: - prefix: str match_string: str pass class CommandManager: session: Session + registered_command = {} + # prefix -> Union[main_name, aliases] -> action - def __init__(self, session): + def __init__(self, + session: Session, + listenEvents=("GroupMessage", "FriendMessage")): self.session = Session + def newCommand(self, prefix="/", addon_parser={}): - pass \ No newline at end of file + pass + + def event_listener(self, context): + """用于监听事件, 并做出分析, 解析到相应的 Command 上. + """ + context.message.messageChain: MessageChain + context.message.messageChain.getFirstComponent(Plain) \ No newline at end of file diff --git a/mirai/event/builtins.py b/mirai/event/builtins.py index 2de9712..5a6dca7 100644 --- a/mirai/event/builtins.py +++ b/mirai/event/builtins.py @@ -3,7 +3,7 @@ from mirai.session import Session from pydantic import BaseModel -class UnexceptedException(BaseModel): +class UnexpectedException(BaseModel): error: Exception event: InternalEvent session: Session diff --git a/mirai/exceptions.py b/mirai/exceptions.py index a5d5135..f2ae6d3 100644 --- a/mirai/exceptions.py +++ b/mirai/exceptions.py @@ -1,2 +1,5 @@ class NetworkError(Exception): + pass + +class UnknownTarget(Exception): pass \ No newline at end of file diff --git a/mirai/message/types.py b/mirai/message/types.py index 227ad51..6b4b348 100644 --- a/mirai/message/types.py +++ b/mirai/message/types.py @@ -13,7 +13,6 @@ class MessageItemType(Enum): class FriendMessage(BaseModel): type: MessageItemType = "FriendMessage" - message_id: int messageChain: T.Optional[MessageChain] sender: Friend diff --git a/mirai/misc.py b/mirai/misc.py index 66176bb..ac41fad 100644 --- a/mirai/misc.py +++ b/mirai/misc.py @@ -11,21 +11,21 @@ def assertOperatorSuccess(result, raise_exception=False, return_as_is=False): else: if result['code'] != 0: raise { - 1: EnvironmentError, - 2: EnvironmentError, - 3: EnvironmentError, - 4: ConnectionRefusedError, - 5: ValueError, - 10: PermissionError, - 400: RuntimeError + 1: EnvironmentError, + 2: EnvironmentError, + 3: EnvironmentError, + 4: ConnectionRefusedError, + 5: ValueError, + 10: PermissionError, + 400: RuntimeError }[result['code']](f"""invaild stdin: { { - 1: "wrong auth key", - 2: "unknown qq account", - 3: "invaild session key", - 4: "disabled session key", - 5: "unknown receiver target", - 10: "permission denied", - 400: "wrong arguments" + 1: "wrong auth key", + 2: "unknown qq account", + 3: "invaild session key", + 4: "disabled session key", + 5: "unknown receiver target", + 10: "permission denied", + 400: "wrong arguments" }[result['code']] }""") else: if return_as_is: diff --git a/mirai/session.py b/mirai/session.py index e8bad7c..87c35d4 100644 --- a/mirai/session.py +++ b/mirai/session.py @@ -2,7 +2,7 @@ from urllib import parse from .network import fetch, session from .protocol import MiraiProtocol -from .group import Group +from .group import Group, Member from .friend import Friend from .message.types import FriendMessage, GroupMessage, MessageTypes, MessageItemType from .event import InternalEvent, ExternalEvent, ExternalEventTypes, ExternalEvents @@ -12,8 +12,14 @@ import random import traceback from mirai.logger import message as MessageLogger, event as EventLogger -from mirai.misc import printer +from mirai.misc import printer, raiser +from .message import components import inspect +from functools import partial +import copy +from .depends import Depends + +_T = T.TypeVar("T") class Session(MiraiProtocol): cache_options: T.Dict[str, bool] = {} @@ -138,7 +144,7 @@ async def __aexit__(self, exc_type, exc, tb): await self.close_session(ignoreError=True) await session.close() - async def get_tasks(self) -> T.Awaitable: + def get_tasks(self) -> T.Awaitable: "用于为外部的事件循环注入 event_runner 和 message_polling" async def connect(): with self.shared_lock: @@ -218,12 +224,12 @@ async def event_runner(self, exit_signal_status, queue: asyncio.Queue): try: condition_result = (not pre_condition) or (pre_condition(event_context.body)) except Exception as e: - if event_context.name != "UnexceptedException": + if event_context.name != "UnexpectedException": #print("error: by pre:", event_context.name) EventLogger.error(f"a error threw by {event_context.name}'s condition.") await queue.put(InternalEvent( - name="UnexceptedException", - body=UnexceptedException( + name="UnexpectedException", + body=UnexpectedException( error=e, event=event_context, session=self @@ -258,17 +264,25 @@ async def event_runner(self, exit_signal_status, queue: asyncio.Queue): ) else: WorkingContext.set("Unknown") - EventLogger.warning("a unknown event is handling...") - context_body = event_context.body + EventLogger.error("a unknown event was carried") + internal_context_object.set(context_body) # 设置完毕. try: - await run_body(context_body) + annotations_mapping = self.gen_annotations_mapping(event_context) + translated_mapping = { + k: annotations_mapping[v](k)\ + for k, v in run_body.__annotations__.items()\ + if k != "return" + } + await run_body(**translated_mapping) + except (NameError, TypeError) as e: + traceback.print_exc() except Exception as e: - if event_context.name != "UnexceptedException": + if event_context.name != "UnexpectedException": EventLogger.error(f"a error(Exception::{e.__class__.__name__}) threw by {event_context.name}'s processing body.") await queue.put(InternalEvent( - name="UnexceptedException", - body=UnexceptedException( + name="UnexpectedException", + body=UnexpectedException( error=e, event=event_context, session=self @@ -310,7 +324,7 @@ async def joinMainThread(self): def exception_handler(self, exception_class=None, addon_condition=None): return self.receiver( - "UnexceptedException", + "UnexpectedException", lambda context: \ True \ if not exception_class else \ @@ -321,6 +335,43 @@ def exception_handler(self, exception_class=None, addon_condition=None): ) ) + def gen_event_anno(self, event_context): + IReturn = {} + for event_name, event_class in ExternalEvents.__members__.items(): + def warpper(event_context, name, key): + if name != event_context.name: + raise ValueError("cannot look up a non-listened event.") + return event_context.body + IReturn[event_class.value] = partial(warpper, event_context, copy.copy(event_name)) + return IReturn + + def get_annotations_mapping(self, event_context): + return { + Session: lambda k: self, + GroupMessage: lambda k: event_context.body \ + if event_context.name == "GroupMessage" else\ + raiser(ValueError("you cannot setting a unbind argument.")), + FriendMessage: lambda k: event_context.body \ + if event_context.name == "FriendMessage" else\ + raiser(ValueError("you cannot setting a unbind argument.")), + components.Source: lambda k: event_context.body.messageChain.getSource()\ + if event_context.name in MessageTypes else\ + raiser(TypeError("Source is not enable in this type of event.")), + Group: lambda k: event_context.body.sender.group\ + if event_context.name == "GroupMessage" else\ + raiser(ValueError("Group is not enable in this type of event.")), + Friend: lambda k: event_context.body.sender\ + if event_context.name == "FriendMessage" else\ + raiser(ValueError("Friend is not enable in this type of event.")), + Member: lambda k: event_context.body.sender\ + if event_context.name == "GroupMessage" else\ + raiser(ValueError("Group is not enable in this type of event.")), + "Sender": lambda k: event_context.body.sender\ + if event_context.name in MessageTypes else\ + raiser(ValueError("Sender is not enable in this type of event.")), + "Type": lambda k: event_context.name, + **self.gen_event_anno(event_context) + } async def refreshBotGroupsCache(self) -> T.Dict[int, Group]: self.cached_groups = {group.id: group for group in await super().groupList()} @@ -348,7 +399,7 @@ def getEventCurrentName(self, event_value): if inspect.isclass(event_value) and issubclass(event_value, ExternalEvent): # subclass return event_value.__name__ elif isinstance(event_value, ( # normal class - UnexceptedException, + UnexpectedException, GroupMessage, FriendMessage )): @@ -370,5 +421,4 @@ def getEventCurrentName(self, event_value): def registeredEventNames(self): return [self.getEventCurrentName(i) for i in self.event.keys()] - -from .event.builtins import UnexceptedException \ No newline at end of file +from .event.builtins import UnexpectedException \ No newline at end of file diff --git a/setup.py b/setup.py index 24dc710..ffcb196 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="kuriyama", - version='0.1.5', + version='0.1.8', description='A framework for OICQ(QQ, made by Tencent) headless client "Mirai".', author='Chenwe-i-lin', author_email="Chenwe_i_lin@outlook.com", diff --git a/test.py b/test.py index 19a62d4..7eb10ac 100644 --- a/test.py +++ b/test.py @@ -1,104 +1,27 @@ import asyncio -import traceback -from pprint import pprint - +from mirai import Session, Plain, Friend, BotMuteEvent from devtools import debug -from mirai import ( - At, - ExternalEvents, - Face, - FriendMessage, - GroupMessage, - Image, - MessageContextBody, - Plain, - QQFaces, - Session, - UnexceptedException, - ImageType, - Direct -) -from mirai.event import external - -from context_test import is_startwith +authKey = "213we355gdfbaerg" +qq = 208924405 async def main(): - authKey = "213we355gdfbaerg" - qq = 208924405 - - print("???") async with Session(f"mirai://localhost:8070/?authKey={authKey}&qq={qq}") as session: print(session.enabled) + @session.receiver("FriendMessage") + async def event_friendmessage(session: Session, sender: Friend): + await session.sendFriendMessage( + sender.id, + [Plain(text="Hello, world!")] + ) - """ - @session.receiver(GroupMessage) - async def normal_handle(context): - if isinstance(context.message, GroupMessage): - - print(f"[{context.message.sender.group.id}][{context.message.sender.id}]:", context.message.messageChain.toString()) - #debug(context) - if context.message.messageChain.toString().startswith("/raiseAnother"): - raise ValueError("fa") - elif context.message.messageChain.toString().startswith("/raise"): - raise Exception("test") - elif context.message.messageChain.toString().startswith("/test-at"): - await context.session.sendGroupMessage( - context.message.sender.group.id, - [ - At(target=context.message.sender.id), - Plain(text="meow"), - Face(faceId=QQFaces["jingkong"]) - ] - ) - elif context.message.messageChain.toString().startswith("/test-localimage"): - await context.session.sendGroupMessage( - context.message.sender.group.id, - [ - await Image.fromFileSystem("2019-05-04_15.52.03.png", session, ImageType.Group), - Plain(text="faq") - ] - ) - elif context.message.messageChain.toString().startswith("/muteMe"): - await context.session.mute( - context.message.sender.group.id, - context.message.sender.id, - 60 - ) - await asyncio.sleep(5) - await context.session.unmute( - context.message.sender.group.id, - context.message.sender.id - ) - elif context.message.messageChain.toString().startswith("/replyMe"): - debug(await context.session.sendGroupMessage( - context.message.sender.group.id, - "reply da!", - quoteSource=context.message.messageChain.getSource() - )) - if context.message.messageChain.hasComponent(Image): - pass - - @session.receiver(ExternalEvents.MemberMuteEvent) - @session.receiver(external.BotMuteEvent) - async def _(context): - debug(context) - - @session.exception_handler(UnexceptedException) - async def exception_handle(context: UnexceptedException): - debug(context) - """ - @session.receiver(GroupMessage) - async def normal_handle(context): - if is_startwith("/"): - await context.session.sendGroupMessage( - context.message.sender.group.id, - [Plain(text="嗯?你刚才以斜杠开头写了什么啊")] - ) + @session.receiver("BotMuteEvent") + async def event_BotMuteEvent(event: BotMuteEvent): + debug(event) await session.joinMainThread() try: asyncio.run(main()) except KeyboardInterrupt: - exit() + exit() \ No newline at end of file