Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"name": "AliceBot: Examples",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/examples/test.py",
"program": "${workspaceFolder}/examples/main.py",
"console": "integratedTerminal",
"justMyCode": false,
"cwd": "${workspaceFolder}/examples",
Expand Down
25 changes: 6 additions & 19 deletions alicebot/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,25 @@
"""

from abc import ABCMeta, abstractmethod
from typing import TYPE_CHECKING, Any, NamedTuple, Self, override

from pydantic import BaseModel, ConfigDict
from typing import Any, NamedTuple, Self

from alicebot.typing import AnyAdapter, AnyEvent

__all__ = ["Event", "EventHandleOption", "MessageEvent"]


class Event[AdapterT: AnyAdapter](BaseModel, metaclass=ABCMeta):
class Event[AdapterT: AnyAdapter](metaclass=ABCMeta):
"""事件类的基类。

Attributes:
adapter: 产生当前事件的适配器对象。
type: 事件类型。
"""

model_config = ConfigDict(extra="allow")

if TYPE_CHECKING:
adapter: AdapterT
else:
adapter: Any
type: str | None

@override
def __str__(self) -> str:
return f"Event<{self.type}>"

@override
def __repr__(self) -> str:
return self.__str__()
@property
@abstractmethod
def adapter(self) -> AdapterT:
"""产生当前事件的适配器对象。"""


class EventHandleOption(NamedTuple):
Expand Down
16 changes: 13 additions & 3 deletions examples/adapters/console_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,19 @@ class ConsoleAdapterEvent(MessageEvent["ConsoleAdapter"]):
message: 消息内容。
"""

_adapter: "ConsoleAdapter"
message: str

def __init__(self, adapter: "ConsoleAdapter", message: str) -> None:
"""初始化 ConsoleAdapterEvent。"""
self._adapter = adapter
self.message = message

@property
@override
def adapter(self) -> "ConsoleAdapter":
return self._adapter

@override
def get_sender_id(self) -> None:
return None
Expand All @@ -43,9 +54,8 @@ class ConsoleAdapter(PollingAdapter[ConsoleAdapterEvent, None]):
async def on_tick(self) -> None:
print("Please input message: ") # noqa: T201
message = await anyio.to_thread.run_sync(sys.stdin.readline)
await self.handle_event(
ConsoleAdapterEvent(adapter=self, type="message", message=message)
)
event = ConsoleAdapterEvent(adapter=self, message=message.strip())
await self.handle_event(event)

async def send(self, message: str) -> None:
"""发送消息。
Expand Down
18 changes: 13 additions & 5 deletions examples/adapters/http_server_test_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,19 @@
class HttpServerTestEvent(Event["HttpServerTestAdapter"]):
"""HTTP 服务端示例适配器事件类。"""

_adapter: "HttpServerTestAdapter"
message: str

def __init__(self, adapter: "HttpServerTestAdapter", message: str) -> None:
"""初始化 HttpServerTestEvent。"""
self._adapter = adapter
self.message = message

@property
@override
def adapter(self) -> "HttpServerTestAdapter":
return self._adapter


class HttpServerTestAdapter(HttpServerAdapter[HttpServerTestEvent, None]):
"""HTTP 服务端示例适配器类。"""
Expand All @@ -28,10 +39,7 @@ class HttpServerTestAdapter(HttpServerAdapter[HttpServerTestEvent, None]):

@override
async def handle_response(self, request: web.Request) -> web.StreamResponse:
event = HttpServerTestEvent(
adapter=self,
type="message",
message=await request.text(),
)
message = await request.text()
event = HttpServerTestEvent(adapter=self, message=message)
await self.handle_event(event)
return web.Response()
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""APScheduler 适配器事件。"""

# pyright: reportMissingTypeStubs = false
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, override

from apscheduler.job import Job
from apscheduler.triggers.base import BaseTrigger
Expand All @@ -22,11 +22,30 @@
class APSchedulerEvent(Event["APSchedulerAdapter"]):
"""APSchedulerEvent 事件基类。"""

type: str | None = "apscheduler"
if TYPE_CHECKING:
plugin_class: "builtins.type[AnyPlugin]"
else:
plugin_class: Any
type: str = "apscheduler"
_adapter: "APSchedulerAdapter"
_plugin_class: "builtins.type[AnyPlugin]"

def __init__(
self,
*,
adapter: "APSchedulerAdapter",
plugin_class: "builtins.type[AnyPlugin]",
) -> None:
"""初始化 APSchedulerEvent 事件对象。"""
super().__init__()
self._adapter = adapter
self._plugin_class = plugin_class

@property
@override
def adapter(self) -> "APSchedulerAdapter":
return self._adapter

@property
def plugin_class(self) -> "builtins.type[AnyPlugin]":
"""产生当前事件的 Plugin 类。"""
return self._plugin_class

@property
def job(self) -> Job:
Expand All @@ -42,3 +61,11 @@ def trigger(self) -> str | BaseTrigger | None:
def trigger_args(self) -> dict[str, Any] | None:
"""当前事件对应的 Plugin 的 `trigger_args`。"""
return getattr(self.plugin_class, "trigger_args", None)

@override
def __str__(self) -> str:
return f"<{self.__class__.__name__} plugin_class={self.plugin_class.__name__}>"

@override
def __repr__(self) -> str:
return self.__str__()
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ async def handle_cqhttp_event(self, msg: dict[str, Any]) -> None:
msg.get("sub_type"),
)

cqhttp_event = event_class(adapter=self, **msg)
cqhttp_event = event_class(**msg)
cqhttp_event.adapter = self

if cqhttp_event.post_type == "meta_event":
# meta_event 不交由插件处理
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,27 @@ def _get_literal_field(field: FieldInfo | None) -> str | None:
return literal_values[0]


class CQHTTPEvent(Event["CQHTTPAdapter"]):
class CQHTTPEvent(BaseModel, Event["CQHTTPAdapter"]): # pyright: ignore[reportUnsafeMultipleInheritance]
"""CQHTTP 事件基类"""

model_config = ConfigDict(extra="allow")

_adapter: "CQHTTPAdapter"

type: str | None = Field(alias="post_type")
time: int
self_id: int
post_type: str

@property
@override
def adapter(self) -> "CQHTTPAdapter":
return self._adapter

@adapter.setter
def adapter(self, value: "CQHTTPAdapter") -> None:
self._adapter = value

@property
def to_me(self) -> bool:
"""当前事件的 `user_id` 是否等于 `self_id`。"""
Expand All @@ -99,6 +112,14 @@ def get_event_type(cls) -> tuple[str | None, str | None, str | None]:
_get_literal_field(cls.model_fields.get("sub_type")),
)

@override
def __str__(self) -> str:
return f"<{self.__class__.__name__} type={self.type}, time={self.time}, self_id={self.self_id}>"

@override
def __repr__(self) -> str:
return self.__str__()


class MessageEvent(CQHTTPEvent, BaseMessageEvent["CQHTTPAdapter"]):
"""消息事件"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ async def handler(self, request: web.Request) -> web.Response:
logger.error("Illegal http header", sign=request.headers["sign"])
else:
try:
dingtalk_event = DingTalkEvent(adapter=self, **(await request.json()))
dingtalk_event = DingTalkEvent(**(await request.json()))
dingtalk_event.adapter = self
except Exception:
logger.exception("Request parsing error")
return web.Response()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import time
from typing import TYPE_CHECKING, Any, Literal, override

from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field

from alicebot.event import MessageEvent

Expand All @@ -29,11 +29,14 @@ class Text(BaseModel):
content: str


class DingTalkEvent(MessageEvent["DingTalkAdapter"]):
class DingTalkEvent(BaseModel, MessageEvent["DingTalkAdapter"]): # pyright: ignore[reportUnsafeMultipleInheritance]
"""DingTalk 事件基类"""

type: str | None = Field(alias="msgtype")
model_config = ConfigDict(extra="allow")

_adapter: "DingTalkAdapter"

type: str | None = Field(alias="msgtype")
msgtype: str
msgId: str
createAt: str
Expand All @@ -56,6 +59,15 @@ class DingTalkEvent(MessageEvent["DingTalkAdapter"]):
response_msg: None | str | dict[str, Any] | DingTalkMessage = None
response_at: None | dict[str, Any] | DingTalkMessage = None

@property
@override
def adapter(self) -> "DingTalkAdapter":
return self._adapter

@adapter.setter
def adapter(self, value: "DingTalkAdapter") -> None:
self._adapter = value

@property
def message(self) -> DingTalkMessage:
"""返回 message 字段。"""
Expand Down Expand Up @@ -96,3 +108,11 @@ async def reply(
at=at,
)
raise WebhookExpiredError

@override
def __str__(self) -> str:
return f"<{self.__class__.__name__} type={self.type}, time={self.createAt}, self_id={self.chatbotUserId}>"

@override
def __repr__(self) -> str:
return self.__str__()
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ async def handle_mirai_event(self, msg: dict[str, Any]) -> None:
Args:
msg: 接收到的信息。
"""
mirai_event = self.get_event_model(msg["type"])(adapter=self, **msg)
mirai_event = self.get_event_model(msg["type"])(**msg)
mirai_event.adapter = self

if isinstance(mirai_event, MetaEvent):
# meta_event 不交由插件处理
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""事件基类。"""
# pyright: reportIncompatibleVariableOverride=false

from typing import TYPE_CHECKING, Literal
from typing import TYPE_CHECKING, Literal, override

from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict

from alicebot.event import Event

Expand Down Expand Up @@ -56,7 +56,28 @@ class OtherClientSender(BaseModel):
platform: str


class MiraiEvent(Event["MiraiAdapter"]):
class MiraiEvent(BaseModel, Event["MiraiAdapter"]): # pyright: ignore[reportUnsafeMultipleInheritance]
"""Mirai 事件基类"""

model_config = ConfigDict(extra="allow")

_adapter: "MiraiAdapter"

type: str

@property
@override
def adapter(self) -> "MiraiAdapter":
return self._adapter

@adapter.setter
def adapter(self, value: "MiraiAdapter") -> None:
self._adapter = value

@override
def __str__(self) -> str:
return f"<{self.__class__.__name__} type={self.type}>"

@override
def __repr__(self) -> str:
return self.__str__()
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ async def handle_onebot_event(self, msg: dict[str, Any]) -> None:
msg.get("sub_type"),
)

onebot_event = event_class(adapter=self, **msg)
onebot_event = event_class(**msg)
onebot_event.adapter = self

if onebot_event.type == "meta":
# meta_event 不交由插件处理
Expand Down
Loading
Loading