Skip to content

Commit

Permalink
💥kick Source and Quote out of Element
Browse files Browse the repository at this point in the history
  • Loading branch information
BlueGlassBlock committed Nov 3, 2022
1 parent 142fe1d commit 69c61a4
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 126 deletions.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

## 未发布的更新

### 修复

自行实现 `class_property` 以适应 `Python 3.11` 的更改。

### 新增

现在 `Ariadne.default_action` 会作用于所有发送方法。

同时,所有发送方法都可以传入 `action` 参数。

### 更改

现在会使用 30s 一次的自动心跳包。这也许能解决长时间收不到消息导致的伪断连问题。

`RequestEvent.requestId` 改为 `RequestEvent.request_id` (虽然没有人用这个)

现在将全部改用 “实验性消息链” 的行为。(`Source` `Quote` 作为 `MessageEvent` 的属性)

`Source``Quote` 不再是 `Element` 的子类。

### 移除

删除了自 `0.9` 以来弃用的属性。

现在传入 `MessageChain` 作为 `quote` 对象会报错。

## 0.9.8

### 修复
Expand Down
6 changes: 3 additions & 3 deletions src/graia/ariadne/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
)
from .event.mirai import FriendEvent, GroupEvent
from .exception import AriadneConfigurationError, UnknownTarget
from .message import Source
from .message.chain import MessageChain, MessageContainer
from .message.element import Source
from .model import (
Announcement,
FileInfo,
Expand Down Expand Up @@ -225,7 +225,7 @@ async def _event_hook(self, event: MiraiEvent):

if isinstance(event, (MessageEvent, ActiveMessage)):
await cache_set(f"account.{self.account}.message.{int(event)}", event)
if event.message_chain.only(Source):
if not event.message_chain:
event.message_chain.append("<! 不支持的消息类型 !>")

if isinstance(event, FriendEvent):
Expand Down Expand Up @@ -1903,7 +1903,7 @@ async def send_message(
data: Dict[Any, Any] = {"message": MessageChain(message)}
# quote
if isinstance(quote, bool) and quote and isinstance(target, MessageEvent):
data["quote"] = target.message_chain.get_first(Source)
data["quote"] = target.source
elif isinstance(quote, (int, Source)):
data["quote"] = quote
elif isinstance(quote, MessageChain):
Expand Down
4 changes: 2 additions & 2 deletions src/graia/ariadne/entry/message.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Ariadne 消息相关的导入集合"""


from ..message import Quote as Quote
from ..message import Source as Source
from ..message.chain import MessageChain as MessageChain
from ..message.commander import Arg as Arg
from ..message.commander import Commander as Commander
Expand All @@ -23,8 +25,6 @@
from ..message.element import Plain as Plain
from ..message.element import Poke as Poke
from ..message.element import PokeMethods as PokeMethods
from ..message.element import Quote as Quote
from ..message.element import Source as Source
from ..message.element import Voice as Voice
from ..message.formatter import Formatter as Formatter
from ..message.parser.base import ContainKeyword as ContainKeyword
Expand Down
64 changes: 64 additions & 0 deletions src/graia/ariadne/message/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,65 @@
"""本模块提供 Ariadne 消息相关部件."""
from datetime import datetime

from pydantic import Field, validator

from ..model.util import AriadneBaseModel
from ..util import internal_cls
from .chain import MessageChain


@internal_cls()
class Source(AriadneBaseModel):
"""表示消息在一个特定聊天区域内的唯一标识"""

type = "Source"

id: int
"""消息 ID"""

time: datetime
"""发送时间"""

def __int__(self):
return self.id

async def fetch_original(self) -> "MessageChain":
"""尝试从本标记恢复原本的消息链, 有可能失败.
Returns:
MessageChain: 原来的消息链.
"""
from ..app import Ariadne

return (await Ariadne.current().get_message_from_id(self.id)).message_chain


@internal_cls()
class Quote(AriadneBaseModel):
"""表示消息中回复其他消息/用户的部分, 通常包含一个完整的消息链(`origin` 属性)"""

type = "Quote"

id: int
"""引用的消息 ID"""

group_id: int = Field(..., alias="groupId")
"""引用消息所在群号 (好友消息为 0)"""

sender_id: int = Field(..., alias="senderId")
"""发送者 QQ 号"""

target_id: int = Field(..., alias="targetId")
"""原消息的接收者QQ号 (或群号) """

origin: "MessageChain"
"""原来的消息链"""

@validator("origin", pre=True, allow_reuse=True)
def _(cls, v):
from .chain import MessageChain

return MessageChain(v) # no need to parse objects, they are universal!

def as_persistent_string(self) -> str:
return ""
6 changes: 3 additions & 3 deletions src/graia/ariadne/message/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,12 @@ def __getitem__(self, item: Union[Tuple[Type[Element], int], Type[Element], int,
return super().__getitem__(item)

def as_sendable(self) -> Self:
"""将消息链转换为可发送形式 (去除 Source, Quote, File)
"""将消息链转换为可发送形式 (去除 File)
Returns:
MessageChain: 转换后的消息链.
"""
return self.exclude(Source, Quote, File)
return self.exclude(File)

def get(self, element_class: Type[Element_T], count: int = -1) -> List[Element_T]:
res = super().get(element_class, count)
Expand All @@ -204,7 +204,7 @@ def __eq__(self, other: Union[MessageContainer, Self]) -> bool:
return False
if not isinstance(other, MessageChain):
other = MessageChain(other)
return other.as_sendable().content == self.as_sendable().content
return other.content == self.content

def __mul__(self, time: int) -> Self:
result = []
Expand Down
69 changes: 3 additions & 66 deletions src/graia/ariadne/message/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
from graia.amnesia.builtins.aiohttp import AiohttpClientInterface
from graia.amnesia.message import Element as BaseElement
from graia.amnesia.message import Text as BaseText
from pydantic import validator
from pydantic.fields import Field
from typing_extensions import Self

from ..connection.util import UploadMethod
from ..model import AriadneBaseModel, Friend, Member, Stranger
from ..util import escape_bracket, internal_cls
from . import Quote as Quote # noqa: F401
from . import Source as Source # noqa: F401

if TYPE_CHECKING:
from ..event.message import MessageEvent
Expand Down Expand Up @@ -120,66 +121,6 @@ def __eq__(self, other: object) -> bool:
return isinstance(other, (Plain, BaseText)) and self.text == other.text


@internal_cls()
class Source(Element):
"""表示消息在一个特定聊天区域内的唯一标识"""

type: str = "Source"

id: int
"""消息 ID"""

time: datetime
"""发送时间"""

def __int__(self):
return self.id

def as_persistent_string(self) -> str:
return ""

async def fetch_original(self) -> "MessageChain":
"""尝试从本标记恢复原本的消息链, 有可能失败.
Returns:
MessageChain: 原来的消息链.
"""
from ..app import Ariadne

return (await Ariadne.current().get_message_from_id(self.id)).message_chain


@internal_cls()
class Quote(Element):
"""表示消息中回复其他消息/用户的部分, 通常包含一个完整的消息链(`origin` 属性)"""

type: str = "Quote"

id: int
"""引用的消息 ID"""

group_id: int = Field(..., alias="groupId")
"""引用消息所在群号 (好友消息为 0)"""

sender_id: int = Field(..., alias="senderId")
"""发送者 QQ 号"""

target_id: int = Field(..., alias="targetId")
"""原消息的接收者QQ号 (或群号) """

origin: "MessageChain"
"""原来的消息链"""

@validator("origin", pre=True, allow_reuse=True)
def _(cls, v):
from .chain import MessageChain

return MessageChain(v) # no need to parse objects, they are universal!

def as_persistent_string(self) -> str:
return ""


class At(Element):
"""该消息元素用于承载消息中用于提醒/呼唤特定用户的部分."""

Expand Down Expand Up @@ -559,11 +500,7 @@ def __init__(self, *nodes: Union[Iterable[ForwardNode], ForwardNode, "MessageEve
node_list.append(i)
elif isinstance(i, MessageEvent):
if not isinstance(i.sender, Client):
node_list.append(
ForwardNode(
i.sender, time=i.message_chain.get_first(Source).time, message=i.message_chain
)
)
node_list.append(ForwardNode(i.sender, time=i.source.time, message=i.message_chain))
else:
node_list.extend(i)
data.update(nodeList=node_list)
Expand Down
60 changes: 20 additions & 40 deletions src/graia/ariadne/message/parser/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from ...event.message import GroupMessage, MessageEvent
from ...typing import Unions, generic_issubclass, get_origin
from ..chain import MessageChain
from ..element import At, Element, Plain, Quote, Source
from ..element import At, Element, Plain


class ChainDecorator(abc.ABC, Decorator, Derive[MessageChain]):
Expand Down Expand Up @@ -58,15 +58,11 @@ def __init__(self, prefix: Union[str, Iterable[str]]) -> None:
self.prefix: List[str] = [prefix] if isinstance(prefix, str) else list(prefix)

async def __call__(self, chain: MessageChain, _) -> Optional[MessageChain]:
header = chain.include(Quote, Source)
rest: MessageChain = chain.exclude(Quote, Source)
for prefix in self.prefix:
if rest.startswith(prefix):
result = rest.removeprefix(prefix).removeprefix(" ")
break
else:
raise ExecutionStop
return header + result
if chain.startswith(prefix):
return chain.removeprefix(prefix).removeprefix(" ")

raise ExecutionStop


class DetectSuffix(ChainDecorator):
Expand All @@ -81,15 +77,10 @@ def __init__(self, suffix: Union[str, Iterable[str]]) -> None:
self.suffix: List[str] = [suffix] if isinstance(suffix, str) else list(suffix)

async def __call__(self, chain: MessageChain, _) -> Optional[MessageChain]:
header = chain.include(Quote, Source)
rest: MessageChain = chain.exclude(Quote, Source)
for suffix in self.suffix:
if rest.endswith(suffix):
result = rest.removesuffix(suffix).removesuffix(" ")
break
else:
raise ExecutionStop
return header + result
if chain.endswith(suffix):
return chain.removesuffix(suffix).removesuffix(" ")
raise ExecutionStop


class MentionMe(ChainDecorator):
Expand All @@ -111,18 +102,12 @@ async def __call__(self, chain: MessageChain, interface: DispatcherInterface) ->
name = (await ariadne.get_member(interface.event.sender.group, ariadne.account)).name
else:
name = (await ariadne.get_bot_profile()).nickname
header = chain.include(Quote, Source)
rest: MessageChain = chain.exclude(Quote, Source)
first: Element = rest[0]
result: Optional[MessageChain] = None
if isinstance(name, str) and rest and isinstance(first, Plain) and str(first).startswith(name):
result = header + rest.removeprefix(name).removeprefix(" ")
if rest and isinstance(first, At) and first.target == ariadne.account:
result = header + MessageChain(rest.__root__[1:], inline=True).removeprefix(" ")

if result is None:
raise ExecutionStop
return result
first: Element = chain[0]
if isinstance(name, str) and isinstance(first, Plain) and str(first).startswith(name):
return chain.removeprefix(name).removeprefix(" ")
if isinstance(first, At) and first.target == ariadne.account:
return MessageChain(chain.__root__[1:], inline=True).removeprefix(" ")
raise ExecutionStop


class Mention(ChainDecorator):
Expand All @@ -137,23 +122,18 @@ def __init__(self, target: Union[int, str]) -> None:
self.person: Union[int, str] = target

async def __call__(self, chain: MessageChain, _) -> Optional[MessageChain]:
header = chain.include(Quote, Source)
rest: MessageChain = chain.exclude(Quote, Source)
first: Element = rest[0]
result: Optional[MessageChain] = None
first: Element = chain[0]
if (
rest
chain
and isinstance(first, Plain)
and isinstance(self.person, str)
and str(first).startswith(self.person)
):
result = header + rest.removeprefix(self.person).removeprefix(" ")
if rest and isinstance(first, At) and isinstance(self.person, int) and first.target == self.person:
result = header + MessageChain(rest.__root__[1:], inline=True).removeprefix(" ")
return chain.removeprefix(self.person).removeprefix(" ")
if isinstance(first, At) and isinstance(self.person, int) and first.target == self.person:
return MessageChain(chain.__root__[1:], inline=True).removeprefix(" ")

if result is None:
raise ExecutionStop
return result
raise ExecutionStop


class ContainKeyword(ChainDecorator):
Expand Down
Loading

0 comments on commit 69c61a4

Please sign in to comment.