hyper-bot 0.82.4__tar.gz → 0.90.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hyper_bot-0.82.4/src/hyper_bot.egg-info → hyper_bot-0.90.0}/PKG-INFO +1 -1
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/pyproject.toml +19 -1
- {hyper_bot-0.82.4 → hyper_bot-0.90.0/src/hyper_bot.egg-info}/PKG-INFO +1 -1
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyper_bot.egg-info/SOURCES.txt +6 -2
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyper_bot.egg-info/dependency_links.txt +0 -0
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyper_bot.egg-info/requires.txt +0 -0
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyper_bot.egg-info/top_level.txt +0 -0
- hyper_bot-0.90.0/src/hyperot/LecAdapters/Milky.py +336 -0
- hyper_bot-0.90.0/src/hyperot/LecAdapters/MilkyLib/Manager.py +25 -0
- {hyper_bot-0.82.4/src/hyperot/LecAdapters/OneBotLib → hyper_bot-0.90.0/src/hyperot/LecAdapters/MilkyLib}/Res.py +14 -15
- hyper_bot-0.90.0/src/hyperot/LecAdapters/MilkyLib/translator.py +424 -0
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/LecAdapters/OneBot.py +51 -92
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/LecAdapters/OneBotLib/Manager.py +4 -8
- {hyper_bot-0.82.4/src/hyperot/LecAdapters/MilkyLib → hyper_bot-0.90.0/src/hyperot/LecAdapters/OneBotLib}/Res.py +9 -41
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/__init__.py +42 -36
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/adapters/__init__.py +0 -0
- hyper_bot-0.90.0/src/hyperot/adapters/builtins.py +29 -0
- hyper_bot-0.90.0/src/hyperot/adapters/common.py +6 -0
- hyper_bot-0.90.0/src/hyperot/adapters/listener.py +75 -0
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/adapters/obuilder.py +64 -120
- hyper_bot-0.90.0/src/hyperot/adapters/res.py +18 -0
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/common.py +7 -8
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/configurator.py +22 -18
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/events.py +203 -47
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/hyperogger.py +13 -8
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/listener.py +1 -1
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/network.py +23 -15
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/segments.py +72 -75
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/__init__.py +0 -1
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/apiresponse.py +23 -22
- hyper_bot-0.82.4/src/hyperot/utils/ArkSignHelper.py → hyper_bot-0.90.0/src/hyperot/utils/ark_sign_helper.py +27 -30
- hyper_bot-0.90.0/src/hyperot/utils/errors.py +33 -0
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/hypetyping.py +2 -2
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/screens.py +6 -12
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/typextensions.py +9 -21
- hyper_bot-0.90.0/tests/test_events.py +107 -0
- hyper_bot-0.90.0/tests/test_milky.py +710 -0
- hyper_bot-0.90.0/tests/test_segments.py +67 -0
- hyper_bot-0.90.0/tests/test_utils.py +93 -0
- hyper_bot-0.82.4/src/hyperot/LecAdapters/Milky.py +0 -215
- hyper_bot-0.82.4/src/hyperot/LecAdapters/MilkyLib/Manager.py +0 -13
- hyper_bot-0.82.4/src/hyperot/LecAdapters/MilkyLib/translator.py +0 -217
- hyper_bot-0.82.4/src/hyperot/adapters/builtins.py +0 -15
- hyper_bot-0.82.4/src/hyperot/adapters/common.py +0 -8
- hyper_bot-0.82.4/src/hyperot/adapters/listener.py +0 -95
- hyper_bot-0.82.4/src/hyperot/adapters/res.py +0 -22
- hyper_bot-0.82.4/src/hyperot/utils/errors.py +0 -27
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/LICENSE +0 -0
- {hyper_bot-0.82.4 → hyper_bot-0.90.0}/setup.cfg +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hyper-bot"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.90.0"
|
|
8
8
|
description = "稳定高效、易于开发的QQ Bot框架"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Harcic", email = "harcic@outlook.com" },
|
|
@@ -25,3 +25,21 @@ dependencies = [
|
|
|
25
25
|
[tool.setuptools.packages.find]
|
|
26
26
|
where = ["src"]
|
|
27
27
|
include = ["hyperot*"]
|
|
28
|
+
|
|
29
|
+
[tool.ruff]
|
|
30
|
+
target-version = "py311"
|
|
31
|
+
line-length = 120
|
|
32
|
+
|
|
33
|
+
[tool.ruff.lint]
|
|
34
|
+
# 工作区挂载在 NTFS (fuseblk) 上,无法表示可执行位,文件总是 rwxrwxrwx。
|
|
35
|
+
# git index 中已通过 `git update-index --chmod=-x` 修正为 644,此处忽略该检查。
|
|
36
|
+
extend-per-file-ignores = { "*.py" = ["EXE002"] }
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest>=9.1.1",
|
|
41
|
+
"ruff>=0.16.1",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
testpaths = ["tests"]
|
|
@@ -26,10 +26,14 @@ src/hyperot/adapters/common.py
|
|
|
26
26
|
src/hyperot/adapters/listener.py
|
|
27
27
|
src/hyperot/adapters/obuilder.py
|
|
28
28
|
src/hyperot/adapters/res.py
|
|
29
|
-
src/hyperot/utils/ArkSignHelper.py
|
|
30
29
|
src/hyperot/utils/__init__.py
|
|
31
30
|
src/hyperot/utils/apiresponse.py
|
|
31
|
+
src/hyperot/utils/ark_sign_helper.py
|
|
32
32
|
src/hyperot/utils/errors.py
|
|
33
33
|
src/hyperot/utils/hypetyping.py
|
|
34
34
|
src/hyperot/utils/screens.py
|
|
35
|
-
src/hyperot/utils/typextensions.py
|
|
35
|
+
src/hyperot/utils/typextensions.py
|
|
36
|
+
tests/test_events.py
|
|
37
|
+
tests/test_milky.py
|
|
38
|
+
tests/test_segments.py
|
|
39
|
+
tests/test_utils.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from typing import NoReturn
|
|
7
|
+
|
|
8
|
+
from .. import common, configurator, events, hyperogger, segments
|
|
9
|
+
from ..events import *
|
|
10
|
+
from ..utils import errors
|
|
11
|
+
from ..utils.apiresponse import *
|
|
12
|
+
from .MilkyLib.Manager import Packet
|
|
13
|
+
from .MilkyLib.translator import (
|
|
14
|
+
MilkyHttpConnection,
|
|
15
|
+
message_translator,
|
|
16
|
+
msg_deid,
|
|
17
|
+
msg_enid,
|
|
18
|
+
node_list_to_milky_forward,
|
|
19
|
+
to_milky_message,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
config = configurator.BotConfig.get("hyper-bot")
|
|
23
|
+
logger = hyperogger.Logger()
|
|
24
|
+
logger.set_level(config.log_level)
|
|
25
|
+
listener_ran = False
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Actions:
|
|
29
|
+
def __init__(self, cnt: MilkyHttpConnection):
|
|
30
|
+
self.connection = cnt
|
|
31
|
+
|
|
32
|
+
class CustomAction:
|
|
33
|
+
def __init__(self, cnt_i: MilkyHttpConnection):
|
|
34
|
+
self.connection = cnt_i
|
|
35
|
+
|
|
36
|
+
def __getattr__(self, item) -> Callable:
|
|
37
|
+
async def wrapper(**kwargs) -> dict | None:
|
|
38
|
+
res = await Packet(str(item), **kwargs).send_to(self.connection)
|
|
39
|
+
return res.get("data")
|
|
40
|
+
|
|
41
|
+
return wrapper
|
|
42
|
+
|
|
43
|
+
self.custom = CustomAction(self.connection)
|
|
44
|
+
|
|
45
|
+
async def send_msg(
|
|
46
|
+
self, message: common.Message | str, group_id: int | None = None, user_id: int | None = None
|
|
47
|
+
) -> common.Ret[MsgSendRsp]:
|
|
48
|
+
if isinstance(message, str):
|
|
49
|
+
message = common.Message(segments.Text(message))
|
|
50
|
+
elif not isinstance(message, common.Message):
|
|
51
|
+
message = common.Message(message)
|
|
52
|
+
if group_id is not None:
|
|
53
|
+
endpoint, scene, peer = "send_group_message", 1, group_id
|
|
54
|
+
elif user_id is not None:
|
|
55
|
+
endpoint, scene, peer = "send_private_message", 0, user_id
|
|
56
|
+
else:
|
|
57
|
+
raise errors.ArgsInvalidError("'send' API requires 'group_id' or 'user_id' but none of them are provided.")
|
|
58
|
+
res = await Packet(
|
|
59
|
+
endpoint,
|
|
60
|
+
**{("group_id" if group_id is not None else "user_id"): peer},
|
|
61
|
+
message=to_milky_message(message),
|
|
62
|
+
).send_to(self.connection)
|
|
63
|
+
ret = common.Ret(res)
|
|
64
|
+
ret.data = MsgSendRsp({"message_id": msg_enid(scene, res["data"]["message_seq"], peer)})
|
|
65
|
+
logger.info(f"向{'群 ' + str(peer) if scene else '用户 ' + str(peer)}发送:{message!s}")
|
|
66
|
+
return ret
|
|
67
|
+
|
|
68
|
+
async def send_group_msg(
|
|
69
|
+
self, message: common.Message | str, group_id: int | None = None
|
|
70
|
+
) -> common.Ret[MsgSendRsp]:
|
|
71
|
+
return await self.send_msg(message, group_id=group_id)
|
|
72
|
+
|
|
73
|
+
async def send_private_msg(
|
|
74
|
+
self, message: common.Message | str, user_id: int | None = None
|
|
75
|
+
) -> common.Ret[MsgSendRsp]:
|
|
76
|
+
return await self.send_msg(message, user_id=user_id)
|
|
77
|
+
|
|
78
|
+
async def del_msg(self, message_id: int) -> None:
|
|
79
|
+
scene, seq, peer = msg_deid(message_id)
|
|
80
|
+
if scene == 0:
|
|
81
|
+
await Packet("recall_private_message", user_id=peer, message_seq=seq).send_to(self.connection)
|
|
82
|
+
else:
|
|
83
|
+
await Packet("recall_group_message", group_id=peer, message_seq=seq).send_to(self.connection)
|
|
84
|
+
logger.info(f"撤回消息 {message_id}")
|
|
85
|
+
|
|
86
|
+
async def set_group_kick(self, group_id: int, user_id: int) -> None:
|
|
87
|
+
await Packet("kick_group_member", group_id=group_id, user_id=user_id).send_to(self.connection)
|
|
88
|
+
logger.info(f"将用户 {user_id} 移出群 {group_id}")
|
|
89
|
+
|
|
90
|
+
async def set_group_ban(self, group_id: int, user_id: int, duration: int = 60) -> None:
|
|
91
|
+
await Packet("set_group_member_mute", group_id=group_id, user_id=user_id, duration=duration).send_to(
|
|
92
|
+
self.connection
|
|
93
|
+
)
|
|
94
|
+
logger.info(f"在群 {group_id} 将用户 {user_id} 禁言 {duration}s")
|
|
95
|
+
|
|
96
|
+
async def get_login_info(self) -> common.Ret[GetLoginInfoRsp]:
|
|
97
|
+
res = await Packet("get_login_info").send_to(self.connection)
|
|
98
|
+
ret = common.Ret(res)
|
|
99
|
+
ret.data = GetLoginInfoRsp({"user_id": res["data"]["uin"], "nickname": res["data"]["nickname"]})
|
|
100
|
+
return ret
|
|
101
|
+
|
|
102
|
+
async def get_version_info(self) -> common.Ret[GetVerInfoRsp]:
|
|
103
|
+
res = await Packet("get_impl_info").send_to(self.connection)
|
|
104
|
+
ret = common.Ret(res)
|
|
105
|
+
ret.data = GetVerInfoRsp(
|
|
106
|
+
{
|
|
107
|
+
"app_name": res["data"]["impl_name"],
|
|
108
|
+
"app_version": res["data"]["impl_version"],
|
|
109
|
+
"protocol_version": res["data"]["milky_version"],
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
return ret
|
|
113
|
+
|
|
114
|
+
async def send_forward_msg(self, message: common.Message) -> common.Ret[SendForwardRsp]:
|
|
115
|
+
raise NotImplementedError("Milky adapter 发送合并转发请使用 send_group_forward_msg")
|
|
116
|
+
|
|
117
|
+
async def get_forward_msg(self, sid: str) -> common.Ret[common.Message]:
|
|
118
|
+
res = await Packet("get_forwarded_messages", forward_id=sid).send_to(self.connection)
|
|
119
|
+
nodes = []
|
|
120
|
+
for fm in res["data"]["messages"]:
|
|
121
|
+
content = events.gen_message({"message": message_translator(fm.get("segments", []), 0, 0)})
|
|
122
|
+
nodes.append(
|
|
123
|
+
segments.Node(
|
|
124
|
+
user_id=str(fm.get("message_seq", 0)), nickname=fm.get("sender_name", ""), content=content
|
|
125
|
+
)
|
|
126
|
+
)
|
|
127
|
+
ret = common.Ret(res)
|
|
128
|
+
ret.data = common.Message(*nodes)
|
|
129
|
+
return ret
|
|
130
|
+
|
|
131
|
+
async def forward_solve(self, message: common.Message) -> common.Message:
|
|
132
|
+
for i in message:
|
|
133
|
+
if isinstance(i, segments.Forward):
|
|
134
|
+
data = await self.get_forward_msg(i.id)
|
|
135
|
+
return data.data
|
|
136
|
+
raise ValueError("Incorrect message type")
|
|
137
|
+
|
|
138
|
+
async def send_group_forward_msg(self, group_id: int, message: common.Message) -> common.Ret[SendGrpForwardRsp]:
|
|
139
|
+
res = await Packet("send_group_msg", group_id=group_id, message=[node_list_to_milky_forward(message)]).send_to(
|
|
140
|
+
self.connection
|
|
141
|
+
)
|
|
142
|
+
ret = common.Ret(res)
|
|
143
|
+
ret.data = SendGrpForwardRsp({"message_id": res["data"]["message_seq"], "forward_id": ""})
|
|
144
|
+
return ret
|
|
145
|
+
|
|
146
|
+
async def set_group_add_request(
|
|
147
|
+
self, flag: str, sub_type: str, approve: bool, reason: str = "Not Mentioned"
|
|
148
|
+
) -> None:
|
|
149
|
+
group_id, seq = (int(x) for x in flag.split(":"))
|
|
150
|
+
notification_type = "join_request" if sub_type == "add" else "invited_join_request"
|
|
151
|
+
endpoint = "accept_group_request" if approve else "reject_group_request"
|
|
152
|
+
params = {
|
|
153
|
+
"notification_seq": seq,
|
|
154
|
+
"notification_type": notification_type,
|
|
155
|
+
"group_id": group_id,
|
|
156
|
+
}
|
|
157
|
+
if not approve:
|
|
158
|
+
params["reason"] = reason
|
|
159
|
+
await Packet(endpoint, **params).send_to(self.connection)
|
|
160
|
+
logger.info(f"由于 {reason},{'通过' if approve else '拒绝'} {flag} 请求")
|
|
161
|
+
|
|
162
|
+
async def get_stranger_info(self, user_id: int) -> common.Ret[GetStrInfoRsp]:
|
|
163
|
+
res = await Packet("get_user_profile", user_id=user_id).send_to(self.connection)
|
|
164
|
+
ret = common.Ret(res)
|
|
165
|
+
d = res["data"]
|
|
166
|
+
ret.data = GetStrInfoRsp(
|
|
167
|
+
{
|
|
168
|
+
"user_id": user_id,
|
|
169
|
+
"nickname": d.get("nickname", ""),
|
|
170
|
+
"sex": d.get("sex", "unknown"),
|
|
171
|
+
"age": d.get("age", 0),
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
return ret
|
|
175
|
+
|
|
176
|
+
async def get_group_member_info(self, group_id: int, user_id: int) -> common.Ret[GetGrpMemInfoRsp]:
|
|
177
|
+
res = await Packet("get_group_member_info", group_id=group_id, user_id=user_id).send_to(self.connection)
|
|
178
|
+
ret = common.Ret(res)
|
|
179
|
+
d = res["data"].get("member", {})
|
|
180
|
+
ret.data = GetGrpMemInfoRsp(
|
|
181
|
+
{
|
|
182
|
+
"group_id": d.get("group_id", group_id),
|
|
183
|
+
"user_id": d.get("user_id", user_id),
|
|
184
|
+
"nickname": d.get("nickname", ""),
|
|
185
|
+
"card": d.get("card", ""),
|
|
186
|
+
"sex": d.get("sex", "unknown"),
|
|
187
|
+
"age": 0,
|
|
188
|
+
"area": "",
|
|
189
|
+
"join_time": d.get("join_time", 0),
|
|
190
|
+
"last_sent_time": d.get("last_sent_time", 0),
|
|
191
|
+
"level": str(d.get("level", "")),
|
|
192
|
+
"role": d.get("role", "member"),
|
|
193
|
+
"unfriendly": False,
|
|
194
|
+
"title": d.get("title", ""),
|
|
195
|
+
"title_expire_time": 0,
|
|
196
|
+
"card_changeable": False,
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
return ret
|
|
200
|
+
|
|
201
|
+
async def get_group_info(self, group_id: int) -> common.Ret[GetGrpInfoRsp]:
|
|
202
|
+
res = await Packet("get_group_info", group_id=group_id).send_to(self.connection)
|
|
203
|
+
ret = common.Ret(res)
|
|
204
|
+
d = res["data"].get("group", {})
|
|
205
|
+
ret.data = GetGrpInfoRsp(
|
|
206
|
+
{
|
|
207
|
+
"group_id": d.get("group_id", group_id),
|
|
208
|
+
"group_name": d.get("group_name", ""),
|
|
209
|
+
"member_count": d.get("member_count", 0),
|
|
210
|
+
"max_member_count": d.get("max_member_count", 0),
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
return ret
|
|
214
|
+
|
|
215
|
+
async def get_status(self) -> common.Ret:
|
|
216
|
+
return common.Ret({"status": "ok", "retcode": 0, "data": {}})
|
|
217
|
+
|
|
218
|
+
async def set_essence_msg(self, message_id: int) -> None:
|
|
219
|
+
scene, seq, peer = msg_deid(message_id)
|
|
220
|
+
if scene != 1:
|
|
221
|
+
raise ValueError("Only group messages can be set as essence")
|
|
222
|
+
await Packet("set_group_essence_message", group_id=peer, message_seq=seq, is_set=True).send_to(self.connection)
|
|
223
|
+
|
|
224
|
+
async def set_group_special_title(self, group_id: int, user_id: int, title: str) -> None:
|
|
225
|
+
await Packet("set_group_member_special_title", group_id=group_id, user_id=user_id, special_title=title).send_to(
|
|
226
|
+
self.connection
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
async def get_msg(self, msg_id: int) -> common.Ret[GetMsgRsp]:
|
|
230
|
+
scene, seq, peer = msg_deid(msg_id)
|
|
231
|
+
message_scene = "friend" if scene == 0 else "group"
|
|
232
|
+
res = await Packet("get_message", message_scene=message_scene, peer_id=peer, message_seq=seq).send_to(
|
|
233
|
+
self.connection
|
|
234
|
+
)
|
|
235
|
+
ret = common.Ret(res)
|
|
236
|
+
d = res["data"]
|
|
237
|
+
ret.data = GetMsgRsp(
|
|
238
|
+
{
|
|
239
|
+
"time": d.get("time", 0),
|
|
240
|
+
"message_type": "group" if d.get("message_scene") == "group" else "private",
|
|
241
|
+
"message_id": 0,
|
|
242
|
+
"real_id": d.get("message_seq", 0),
|
|
243
|
+
"sender": d.get("group_member", d.get("friend", {})),
|
|
244
|
+
"message": message_translator(d.get("segments", []), d.get("peer_id", 0), scene),
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
return ret
|
|
248
|
+
|
|
249
|
+
async def send_callback(self, group_id: int, bot_id: int, data: dict) -> None:
|
|
250
|
+
raise NotImplementedError("Milky adapter does not support send_callback")
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
async def tester(message_data: Event | HyperNotify, actions: Actions) -> None: ...
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
async def __handler(data: dict | HyperNotify | None, actions: Actions) -> None:
|
|
257
|
+
if data is None:
|
|
258
|
+
return
|
|
259
|
+
try:
|
|
260
|
+
if isinstance(data, dict):
|
|
261
|
+
await handler(events.em.new(data), actions)
|
|
262
|
+
else:
|
|
263
|
+
await handler(data, actions)
|
|
264
|
+
except Exception:
|
|
265
|
+
logger.exception("处理事件时发生异常")
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
handler: Callable = tester
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def reg(func: Callable) -> None:
|
|
272
|
+
global handler
|
|
273
|
+
handler = func
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
connection: MilkyHttpConnection
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
async def run() -> NoReturn:
|
|
280
|
+
global connection, listener_ran
|
|
281
|
+
listener_ran = True
|
|
282
|
+
try:
|
|
283
|
+
if handler is tester:
|
|
284
|
+
raise errors.ListenerNotRegisteredError("No handler registered")
|
|
285
|
+
if not isinstance(config.connection, configurator.MilkyConnection):
|
|
286
|
+
raise TypeError("Milky 协议需要 MilkyConnection 类型的连接配置")
|
|
287
|
+
connection = MilkyHttpConnection(
|
|
288
|
+
f"ws://{config.connection.host}:{config.connection.port}", auth=config.connection.auth
|
|
289
|
+
)
|
|
290
|
+
retried = 0
|
|
291
|
+
|
|
292
|
+
while True:
|
|
293
|
+
try:
|
|
294
|
+
await connection.connect()
|
|
295
|
+
except (ConnectionRefusedError, TimeoutError, OSError):
|
|
296
|
+
if retried >= config.connection.retries:
|
|
297
|
+
logger.critical(f"重试次数达到最大值({config.connection.retries}),退出")
|
|
298
|
+
break
|
|
299
|
+
|
|
300
|
+
logger.warning(f"连接建立失败,3秒后重试({retried}/{config.connection.retries})")
|
|
301
|
+
retried += 1
|
|
302
|
+
await asyncio.sleep(3)
|
|
303
|
+
continue
|
|
304
|
+
retried = 0
|
|
305
|
+
logger.info(f"成功在 {connection.url} 建立连接")
|
|
306
|
+
actions = Actions(connection)
|
|
307
|
+
start_data = HyperListenerStartNotify(
|
|
308
|
+
time_now=int(time.time()), notify_type="listener_start", connection=connection
|
|
309
|
+
)
|
|
310
|
+
asyncio.create_task(__handler(start_data, actions))
|
|
311
|
+
while True:
|
|
312
|
+
try:
|
|
313
|
+
data = await connection.recv()
|
|
314
|
+
except ConnectionResetError:
|
|
315
|
+
logger.error("连接断开")
|
|
316
|
+
break
|
|
317
|
+
except json.decoder.JSONDecodeError:
|
|
318
|
+
logger.error("收到错误的JSON内容")
|
|
319
|
+
continue
|
|
320
|
+
if data is not None:
|
|
321
|
+
asyncio.create_task(__handler(data, actions))
|
|
322
|
+
except KeyboardInterrupt:
|
|
323
|
+
logger.warning("正在退出(Ctrl+C)")
|
|
324
|
+
try:
|
|
325
|
+
await connection.close()
|
|
326
|
+
except Exception:
|
|
327
|
+
logger.exception("关闭连接失败")
|
|
328
|
+
sys.exit()
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def stop() -> None:
|
|
332
|
+
try:
|
|
333
|
+
connection.close()
|
|
334
|
+
except Exception:
|
|
335
|
+
logger.exception("停止监听器时关闭连接失败")
|
|
336
|
+
logger.log("停止运行监听器", level=hyperogger.levels.WARNING)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from ... import configurator, hyperogger, utils
|
|
2
|
+
from .translator import MilkyHttpConnection
|
|
3
|
+
|
|
4
|
+
reports = utils.KeyQueue()
|
|
5
|
+
|
|
6
|
+
config: configurator.BotConfig
|
|
7
|
+
logger: hyperogger.Logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def init() -> None:
|
|
11
|
+
global config, logger
|
|
12
|
+
config = configurator.BotConfig.get("hyper-bot")
|
|
13
|
+
logger = hyperogger.Logger()
|
|
14
|
+
logger.set_level(config.log_level)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Packet:
|
|
18
|
+
def __init__(self, endpoint: str, **kwargs):
|
|
19
|
+
self.endpoint = endpoint
|
|
20
|
+
self.paras = kwargs
|
|
21
|
+
|
|
22
|
+
async def send_to(self, connection: MilkyHttpConnection) -> dict:
|
|
23
|
+
if isinstance(connection, MilkyHttpConnection):
|
|
24
|
+
return await connection.http_send(self.endpoint, self.paras)
|
|
25
|
+
raise TypeError(f"Invalid connection: {connection}")
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from abc import ABC
|
|
2
2
|
|
|
3
3
|
from ...utils.hypetyping import OneBotSegReg
|
|
4
|
+
from .translator import milky_seg_from_dict
|
|
4
5
|
|
|
5
6
|
message_types = {}
|
|
6
7
|
|
|
8
|
+
|
|
7
9
|
class SegmentBase(ABC):
|
|
8
10
|
def __init__(self, *args, **kwargs):
|
|
9
11
|
var = self.__var
|
|
@@ -14,17 +16,17 @@ class SegmentBase(ABC):
|
|
|
14
16
|
arg[list(anns.keys())[list(args).index(i)]] = i
|
|
15
17
|
|
|
16
18
|
if len(kwargs) > 0:
|
|
17
|
-
for i in kwargs:
|
|
19
|
+
for i, v in kwargs.items():
|
|
18
20
|
try:
|
|
19
|
-
arg[i] = anns[i](
|
|
21
|
+
arg[i] = anns[i](v)
|
|
20
22
|
except TypeError:
|
|
21
|
-
arg[i] =
|
|
23
|
+
arg[i] = v
|
|
22
24
|
new_arg = arg.copy()
|
|
23
25
|
|
|
24
26
|
if len(anns) > len(arg):
|
|
25
|
-
for i in anns
|
|
26
|
-
if i not in arg
|
|
27
|
-
if i not in var
|
|
27
|
+
for i in anns:
|
|
28
|
+
if i not in arg:
|
|
29
|
+
if i not in var:
|
|
28
30
|
new_arg[i] = None
|
|
29
31
|
continue
|
|
30
32
|
if not isinstance(var[i], anns[i]):
|
|
@@ -44,7 +46,7 @@ class SegmentBase(ABC):
|
|
|
44
46
|
|
|
45
47
|
cls.__sg_type = sg_type
|
|
46
48
|
cls.__var = dict(vars(cls))
|
|
47
|
-
cls.__anns: dict = cls.__var.get("__annotations__", False) or
|
|
49
|
+
cls.__anns: dict = cls.__var.get("__annotations__", False) or {}
|
|
48
50
|
|
|
49
51
|
def to_str(self) -> str:
|
|
50
52
|
text = summary_tmp
|
|
@@ -83,17 +85,14 @@ class SegmentBase(ABC):
|
|
|
83
85
|
base["data"][i] = getattr(self, i)
|
|
84
86
|
return base
|
|
85
87
|
|
|
88
|
+
def milky_outgoing_seg(self) -> dict:
|
|
89
|
+
return milky_seg_from_dict(self.to_json())
|
|
90
|
+
|
|
86
91
|
def __str__(self) -> str:
|
|
87
92
|
return "__not_set__"
|
|
88
93
|
|
|
89
94
|
def __eq__(self, other) -> bool:
|
|
90
|
-
|
|
91
|
-
return True
|
|
92
|
-
else:
|
|
93
|
-
return False
|
|
95
|
+
return type(self) is type(other) and self.to_json() == other.to_json()
|
|
94
96
|
|
|
95
97
|
def __ne__(self, other) -> bool:
|
|
96
|
-
|
|
97
|
-
return False
|
|
98
|
-
else:
|
|
99
|
-
return True
|
|
98
|
+
return not (type(self) is type(other) and self.to_json() == other.to_json())
|