Skip to content

Commit

Permalink
✨ support serialize & deserialize UniMessage
Browse files Browse the repository at this point in the history
  • Loading branch information
RF-Tar-Railt committed Aug 4, 2024
1 parent d2aa089 commit 5be8620
Show file tree
Hide file tree
Showing 14 changed files with 243 additions and 30 deletions.
17 changes: 16 additions & 1 deletion pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ dev = [
"nonebot-plugin-send-anything-anywhere>=0.6.1",
"pytest-sugar>=1.0.0",
"pytest-mock>=3.14.0",
"nonebot-plugin-localstore>=0.7.1",
]
[tool.pdm.build]
includes = ["src/nonebot_plugin_alconna"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,8 @@ async def reference(self, seg: Reference, bot: Union[Bot, None]) -> "MessageSegm
content = self.get_message_type()()
if isinstance(node.content, str):
content.extend(self.get_message_type()(node.content))
elif isinstance(node.content, list):
content.extend(await self.export(node.content, bot, True)) # type: ignore
else:
content.extend(node.content)
content.extend(await self.export(node.content, bot, True))
nodes.append(
ForwardMessageBody(
message=PushMessageBody(
Expand Down
4 changes: 3 additions & 1 deletion src/nonebot_plugin_alconna/uniseg/adapters/mirai/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ def forward(self, seg: ForwardSegment):
elif isinstance(node, RefNodeSegment):
nodes.append(RefNode(str(node.ref["id"]), str(node.ref["target"])))
else:
nodes.append(CustomNode(str(node.uid), node.name, node.message, datetime.fromtimestamp(node.time)))
nodes.append(
CustomNode(str(node.uid), node.name, self.generate(node.message), datetime.fromtimestamp(node.time))
)
return Reference()(*nodes)

@build("app")
Expand Down
4 changes: 1 addition & 3 deletions src/nonebot_plugin_alconna/uniseg/adapters/mirai/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,8 @@ async def reference(self, seg: Reference, bot: Union[Bot, None]) -> "MessageSegm
content = self.get_message_type()([])
if isinstance(node.content, str):
content.extend(self.get_message_type()(node.content))
elif isinstance(node.content, list):
content.extend(await self.export(node.content, bot, True)) # type: ignore
else:
content.extend(node.content)
content.extend(await self.export(node.content, bot, True))
nodes.append(
MessageSegment.custom_node(
int(node.uid),
Expand Down
4 changes: 3 additions & 1 deletion src/nonebot_plugin_alconna/uniseg/adapters/mirai2/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ def forward(self, seg: MessageSegment):
elif "messageRef" in node:
nodes.append(RefNode(node["messageRef"]["messageId"], node["messageRef"]["target"]))
else:
nodes.append(CustomNode(node["senderId"], node["senderName"], node["time"], node["messageChain"]))
nodes.append(
CustomNode(node["senderId"], node["senderName"], self.generate(node["messageChain"]), node["time"])
)
return Reference(seg.data.get("messageId"))(*nodes)

@build(MessageType.APP)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,8 @@ async def reference(self, seg: Reference, bot: Union[Bot, None]) -> "MessageSegm
content = self.get_message_type()([])
if isinstance(node.content, str):
content.extend(self.get_message_type()(node.content))
elif isinstance(node.content, list):
content.extend(await self.export(node.content, bot, True)) # type: ignore
else:
content.extend(node.content)
content.extend(await self.export(node.content, bot, True))
nodes.append(
{
"senderId": node.uid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,13 @@ async def reference(self, seg: Reference, bot: Union[Bot, None]) -> "MessageSegm
content = self.get_message_type()()
if isinstance(node.content, str):
content.extend(self.get_message_type()(node.content))
elif isinstance(node.content, list):
content.extend(await self.export(node.content, bot, True)) # type: ignore
else:
content.extend(node.content)
content.extend(await self.export(node.content, bot, True))
nodes.append(
MessageSegment.node_custom(
user_id=int(node.uid),
nickname=node.name,
content=[asdict(m) for m in content], # type: ignore
content=content, # type: ignore
)
)
return nodes # type: ignore
Expand Down
4 changes: 1 addition & 3 deletions src/nonebot_plugin_alconna/uniseg/adapters/red/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,8 @@ async def reference(self, seg: Reference, bot: Union[Bot, None]) -> "MessageSegm
content = self.get_message_type()()
if isinstance(node.content, str):
content.extend(self.get_message_type()(node.content))
elif isinstance(node.content, list):
content.extend(await self.export(node.content, bot, True)) # type: ignore
else:
content.extend(node.content)
content.extend(await self.export(node.content, bot, True))
nodes.append(ForwardNode(uin=node.uid, name=node.name, time=node.time, message=content))
return MessageSegment.forward(nodes)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,8 @@ async def reference(self, seg: Reference, bot: Union[Bot, None]) -> "MessageSegm
_content.append(MessageSegment.author(node.uid, node.name))
if isinstance(node.content, str):
_content.extend(self.get_message_type()(node.content))
elif isinstance(node.content, list):
_content.extend(await self.export(node.content, bot, True)) # type: ignore
else:
_content.extend(node.content)
_content.extend(await self.export(node.content, bot, True))
content.append(MessageSegment.message(content=_content))

return MessageSegment.message(seg.id, bool(seg.children), content)
Expand Down
4 changes: 0 additions & 4 deletions src/nonebot_plugin_alconna/uniseg/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ async def _auto_fallback(seg: Segment, bot: Union[Bot, None]):
if isinstance(node, CustomNode):
if isinstance(node.content, str):
msg.append(Text(node.content))
elif isinstance(node.content, Message):
msg.extend(Other(ms) for ms in node.content)
else:
msg.extend(node.content)
else:
Expand Down Expand Up @@ -206,8 +204,6 @@ async def export(self, source: Sequence[Segment], bot: Union[Bot, None], fallbac
if isinstance(node, CustomNode):
if isinstance(node.content, str):
message.append(msg_type(node.content))
elif isinstance(node.content, Message):
message.extend(node.content)
else:
message.extend(await self.export(node.content, bot, FallbackStrategy.auto))
else:
Expand Down
49 changes: 49 additions & 0 deletions src/nonebot_plugin_alconna/uniseg/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from io import BytesIO
from pathlib import Path
from copy import deepcopy
from json import dumps, loads
from types import FunctionType
from dataclasses import dataclass
from collections.abc import Iterable, Sequence, Awaitable
Expand Down Expand Up @@ -31,6 +32,7 @@
Emoji,
Hyper,
Image,
Media,
Reply,
Video,
Voice,
Expand All @@ -40,6 +42,7 @@
Keyboard,
Reference,
CustomNode,
get_segment_class,
)

T = TypeVar("T")
Expand Down Expand Up @@ -1405,6 +1408,52 @@ async def finish(
await self.send(target, bot, fallback, at_sender, reply_to, **kwargs)
raise FinishedException

@overload
def dump(self, media_save_dir: Union[str, Path, None] = None) -> list[dict]: ...

@overload
def dump(self, media_save_dir: Union[str, Path, None] = None, json: Literal[True] = True) -> str: ...

def dump(
self, media_save_dir: Union[str, Path, None] = None, json: bool = False
) -> Union[str, list[dict[str, Any]]]:
"""将消息序列化为 JSON 格式
注意:
若不指定 media_save_dir,则会尝试导入 `nonebot_plugin_localstore` 并使用其提供的路径。
否则,将会尝试使用当前工作目录。
Args:
media_save_dir (Union[str, Path, None], optional): 媒体文件保存路径. Defaults to None.
json (bool, optional): 是否返回 JSON 字符串. Defaults to False.
Returns:
Union[str, list[dict]]: 序列化后的消息
"""
result = []
for seg in self:
if isinstance(seg, Media):
result.append(seg.dump(media_save_dir=media_save_dir))
else:
result.append(seg.dump())
return dumps(result, ensure_ascii=False) if json else result

@classmethod
def load(cls, data: Union[str, list[dict[str, Any]]]):
"""从 JSON 数据加载消息
Args:
data (Union[str, list[dict[str, Any]]]): JSON 数据
Returns:
UniMessage: 加载后的消息
"""
if isinstance(data, str):
_data: list[dict[str, Any]] = loads(data)
else:
_data = data
return cls(get_segment_class(seg_data["type"]).load(seg_data) for seg_data in _data)


@dataclass
class Receipt:
Expand Down
Loading

0 comments on commit 5be8620

Please sign in to comment.