satori-python-adapter-onebot11 0.4.2__tar.gz → 0.5.1__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.
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/.mina/adapter_onebot11.toml +4 -4
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/PKG-INFO +7 -6
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/README.md +3 -2
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/pyproject.toml +15 -17
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/__init__.py +2 -0
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/forward.py +77 -68
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/message.py +8 -6
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/reverse.py +81 -70
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/LICENSE +0 -0
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/api.py +0 -0
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/events/__init__.py +0 -0
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/events/base.py +0 -0
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/events/message.py +0 -0
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/events/notice.py +0 -0
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/events/request.py +0 -0
- {satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/src/satori/adapters/onebot11/utils.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
includes = ["src/satori/adapters/onebot11"]
|
|
2
|
-
raw-dependencies = ["satori-python-server<1.4.0,>= 1.3.
|
|
2
|
+
raw-dependencies = ["satori-python-server<1.4.0,>= 1.3.7"]
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = "satori-python-adapter-onebot11"
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.5.1"
|
|
7
7
|
authors = [
|
|
8
8
|
{name = "RF-Tar-Railt", email = "rf_tar_railt@qq.com"}
|
|
9
9
|
]
|
|
@@ -16,11 +16,11 @@ classifiers = [
|
|
|
16
16
|
"Typing :: Typed",
|
|
17
17
|
"Development Status :: 4 - Beta",
|
|
18
18
|
"License :: OSI Approved :: MIT License",
|
|
19
|
-
"Programming Language :: Python :: 3.8",
|
|
20
|
-
"Programming Language :: Python :: 3.9",
|
|
21
19
|
"Programming Language :: Python :: 3.10",
|
|
22
20
|
"Programming Language :: Python :: 3.11",
|
|
23
21
|
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
24
|
"Operating System :: OS Independent",
|
|
25
25
|
]
|
|
26
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: satori-python-adapter-onebot11
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Satori Protocol SDK for python, adapter for OneBot 11
|
|
5
5
|
Home-page: https://github.com/RF-Tar-Railt/satori-python
|
|
6
6
|
Author-Email: RF-Tar-Railt <rf_tar_railt@qq.com>
|
|
@@ -8,16 +8,16 @@ License: MIT
|
|
|
8
8
|
Classifier: Typing :: Typed
|
|
9
9
|
Classifier: Development Status :: 4 - Beta
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
17
|
Project-URL: Homepage, https://github.com/RF-Tar-Railt/satori-python
|
|
18
18
|
Project-URL: Repository, https://github.com/RF-Tar-Railt/satori-python
|
|
19
19
|
Requires-Python: <4.0,>=3.10
|
|
20
|
-
Requires-Dist: satori-python-server<1.4.0,>=1.3.
|
|
20
|
+
Requires-Dist: satori-python-server<1.4.0,>=1.3.7
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
|
|
23
23
|
# satori-python
|
|
@@ -27,11 +27,11 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
[](https://pypi.org/project/satori-python)
|
|
28
28
|
[](https://www.python.org/)
|
|
29
29
|
|
|
30
|
-
基于 [Satori](https://satori.chat/zh-CN/) 协议的 Python 开发工具包
|
|
30
|
+
基于 [Satori](https://satori.chat/zh-CN/protocol) 协议的 Python 开发工具包
|
|
31
31
|
|
|
32
32
|
## 协议介绍
|
|
33
33
|
|
|
34
|
-
[Satori Protocol](https://satori.chat/zh-CN/)
|
|
34
|
+
[Satori Protocol](https://satori.chat/zh-CN/protocol)
|
|
35
35
|
|
|
36
36
|
### 协议端
|
|
37
37
|
|
|
@@ -77,6 +77,7 @@ pip install satori-python-server
|
|
|
77
77
|
| Console | `pip install satori-python-adapter-console` | satori.adapters.console |
|
|
78
78
|
| Milky | `pip install satori-python-adapter-milky` | satori.adapters.milky.main, satori.adapters.milky.webhook, satori.adapters.milky.sse |
|
|
79
79
|
| QQ | `pip install satori-python-adapter-qq` | satori.adapters.qq.main, satori.adapters.qq.websocket |
|
|
80
|
+
| WxClaw | `pip install satori-python-adapter-wxclaw` | satori.adapters.wxclaw |
|
|
80
81
|
|
|
81
82
|
### 社区适配器
|
|
82
83
|
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
[](https://pypi.org/project/satori-python)
|
|
6
6
|
[](https://www.python.org/)
|
|
7
7
|
|
|
8
|
-
基于 [Satori](https://satori.chat/zh-CN/) 协议的 Python 开发工具包
|
|
8
|
+
基于 [Satori](https://satori.chat/zh-CN/protocol) 协议的 Python 开发工具包
|
|
9
9
|
|
|
10
10
|
## 协议介绍
|
|
11
11
|
|
|
12
|
-
[Satori Protocol](https://satori.chat/zh-CN/)
|
|
12
|
+
[Satori Protocol](https://satori.chat/zh-CN/protocol)
|
|
13
13
|
|
|
14
14
|
### 协议端
|
|
15
15
|
|
|
@@ -55,6 +55,7 @@ pip install satori-python-server
|
|
|
55
55
|
| Console | `pip install satori-python-adapter-console` | satori.adapters.console |
|
|
56
56
|
| Milky | `pip install satori-python-adapter-milky` | satori.adapters.milky.main, satori.adapters.milky.webhook, satori.adapters.milky.sse |
|
|
57
57
|
| QQ | `pip install satori-python-adapter-qq` | satori.adapters.qq.main, satori.adapters.qq.websocket |
|
|
58
|
+
| WxClaw | `pip install satori-python-adapter-wxclaw` | satori.adapters.wxclaw |
|
|
58
59
|
|
|
59
60
|
### 社区适配器
|
|
60
61
|
|
{satori_python_adapter_onebot11-0.4.2 → satori_python_adapter_onebot11-0.5.1}/pyproject.toml
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "satori-python-adapter-onebot11"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.1"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name = "RF-Tar-Railt", email = "rf_tar_railt@qq.com" },
|
|
6
6
|
]
|
|
7
7
|
dependencies = [
|
|
8
|
-
"satori-python-server<1.4.0,>= 1.3.
|
|
8
|
+
"satori-python-server<1.4.0,>= 1.3.7",
|
|
9
9
|
]
|
|
10
10
|
description = "Satori Protocol SDK for python, adapter for OneBot 11"
|
|
11
11
|
readme = "README.md"
|
|
@@ -14,11 +14,11 @@ classifiers = [
|
|
|
14
14
|
"Typing :: Typed",
|
|
15
15
|
"Development Status :: 4 - Beta",
|
|
16
16
|
"License :: OSI Approved :: MIT License",
|
|
17
|
-
"Programming Language :: Python :: 3.8",
|
|
18
|
-
"Programming Language :: Python :: 3.9",
|
|
19
17
|
"Programming Language :: Python :: 3.10",
|
|
20
18
|
"Programming Language :: Python :: 3.11",
|
|
21
19
|
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
22
|
"Operating System :: OS Independent",
|
|
23
23
|
]
|
|
24
24
|
|
|
@@ -38,15 +38,14 @@ build-backend = "mina.backend"
|
|
|
38
38
|
|
|
39
39
|
[dependency-groups]
|
|
40
40
|
dev = [
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"ruff>=0.4.1",
|
|
41
|
+
"black>=26.3.0",
|
|
42
|
+
"ruff>=0.15.1",
|
|
44
43
|
"pre-commit>=3.7.0",
|
|
45
|
-
"fix-future-annotations>=0.5.0",
|
|
46
44
|
"mina-build<0.6,>=0.5.1",
|
|
47
45
|
"pdm-mina>=0.3.2",
|
|
48
46
|
"nonechat<0.7.0,>=0.6.0",
|
|
49
47
|
"uvicorn[standard]>=0.37.0",
|
|
48
|
+
"pydantic>=2.13.1",
|
|
50
49
|
]
|
|
51
50
|
|
|
52
51
|
[tool.pdm.build]
|
|
@@ -60,7 +59,7 @@ excludes = [
|
|
|
60
59
|
|
|
61
60
|
[tool.pdm.scripts.format]
|
|
62
61
|
composite = [
|
|
63
|
-
"
|
|
62
|
+
"ruff check --select I --fix ./src/ ./example/",
|
|
64
63
|
"black ./src/ ./example/",
|
|
65
64
|
"ruff check",
|
|
66
65
|
]
|
|
@@ -74,14 +73,6 @@ line-length = 120
|
|
|
74
73
|
include = "\\.pyi?$"
|
|
75
74
|
extend-exclude = ""
|
|
76
75
|
|
|
77
|
-
[tool.isort]
|
|
78
|
-
profile = "black"
|
|
79
|
-
line_length = 120
|
|
80
|
-
skip_gitignore = true
|
|
81
|
-
extra_standard_library = [
|
|
82
|
-
"typing_extensions",
|
|
83
|
-
]
|
|
84
|
-
|
|
85
76
|
[tool.ruff]
|
|
86
77
|
line-length = 120
|
|
87
78
|
target-version = "py310"
|
|
@@ -91,6 +82,7 @@ exclude = [
|
|
|
91
82
|
"exam2.py",
|
|
92
83
|
"src/satori/_vendor/*",
|
|
93
84
|
]
|
|
85
|
+
respect-gitignore = true
|
|
94
86
|
|
|
95
87
|
[tool.ruff.lint]
|
|
96
88
|
select = [
|
|
@@ -110,6 +102,12 @@ ignore = [
|
|
|
110
102
|
"T201",
|
|
111
103
|
]
|
|
112
104
|
|
|
105
|
+
[tool.ruff.lint.isort]
|
|
106
|
+
extra-standard-library = [
|
|
107
|
+
"typing_extensions",
|
|
108
|
+
]
|
|
109
|
+
force-sort-within-sections = false
|
|
110
|
+
|
|
113
111
|
[tool.pyright]
|
|
114
112
|
pythonPlatform = "All"
|
|
115
113
|
pythonVersion = "3.10"
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
from .forward import OneBot11ForwardAdapter as OneBot11ForwardAdapter
|
|
2
|
+
from .forward import OneBot11ForwardConfig as OneBot11ForwardConfig
|
|
2
3
|
from .reverse import OneBot11ReverseAdapter as OneBot11ReverseAdapter
|
|
4
|
+
from .reverse import OneBot11ReverseConfig as OneBot11ReverseConfig
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
from contextlib import suppress
|
|
5
|
+
from dataclasses import dataclass
|
|
5
6
|
from datetime import datetime
|
|
6
7
|
from typing import cast
|
|
7
8
|
|
|
@@ -25,21 +26,30 @@ from .events.base import events
|
|
|
25
26
|
from .utils import USER_AVATAR_URL, onebot11_event_type
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
@dataclass
|
|
30
|
+
class OneBot11ForwardConfig:
|
|
31
|
+
endpoint: str
|
|
32
|
+
"""连接 OneBot V11协议端的路径"""
|
|
33
|
+
access_token: str | None = None
|
|
34
|
+
"""OneBot V11协议的访问令牌, 默认为空"""
|
|
35
|
+
timeout: float = 60
|
|
36
|
+
"""连接超时时间, 默认为 60 秒"""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class OneBot11ForwardAdapter(BaseAdapter[OneBot11ForwardConfig]):
|
|
29
40
|
|
|
30
41
|
session: ClientSession
|
|
31
42
|
connection: ClientWebSocketResponse | None
|
|
32
43
|
|
|
33
44
|
def __init__(
|
|
34
45
|
self,
|
|
35
|
-
|
|
36
|
-
access_token: str | None = None,
|
|
37
|
-
timeout: float = 60,
|
|
46
|
+
config: OneBot11ForwardConfig,
|
|
38
47
|
):
|
|
39
48
|
super().__init__()
|
|
40
|
-
self.
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
49
|
+
self.config = config
|
|
50
|
+
self.endpoint = URL(config.endpoint)
|
|
51
|
+
self.timeout = config.timeout
|
|
52
|
+
self.access_token = config.access_token
|
|
43
53
|
self.close_signal = asyncio.Event()
|
|
44
54
|
self.response_waiters: dict[str, asyncio.Future] = {}
|
|
45
55
|
self.logins: dict[str, Login] = {}
|
|
@@ -64,74 +74,73 @@ class OneBot11ForwardAdapter(BaseAdapter):
|
|
|
64
74
|
return {"preparing", "blocking", "cleanup"}
|
|
65
75
|
|
|
66
76
|
async def message_handle(self):
|
|
77
|
+
async def _login_add():
|
|
78
|
+
self_info = await self.call_api("get_login_info")
|
|
79
|
+
login = Login(
|
|
80
|
+
sn=0,
|
|
81
|
+
status=LoginStatus.ONLINE,
|
|
82
|
+
adapter="onebot",
|
|
83
|
+
platform="qq-client",
|
|
84
|
+
user=User(
|
|
85
|
+
self_id,
|
|
86
|
+
(self_info or {})["nickname"],
|
|
87
|
+
avatar=USER_AVATAR_URL.format(uin=self_id),
|
|
88
|
+
),
|
|
89
|
+
features=["guild.plain"],
|
|
90
|
+
)
|
|
91
|
+
self.logins[self_id] = login
|
|
92
|
+
await self.server.post(Event(EventType.LOGIN_ADDED, datetime.now(), login))
|
|
93
|
+
|
|
67
94
|
async for connection, data in self.message_receive():
|
|
68
95
|
if echo := data.get("echo"):
|
|
69
96
|
if future := self.response_waiters.get(echo):
|
|
70
97
|
future.set_result(data)
|
|
71
98
|
continue
|
|
72
99
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
elif event_type == "meta_event.lifecycle.enable":
|
|
94
|
-
logger.warning(f"received lifecycle.enable event that is only supported in http adapter: {data}")
|
|
95
|
-
return
|
|
96
|
-
elif event_type == "meta_event.lifecycle.disable":
|
|
97
|
-
logger.warning(f"received lifecycle.disable event that is only supported in http adapter: {data}")
|
|
100
|
+
event_type = onebot11_event_type(data)
|
|
101
|
+
if event_type == "meta_event.lifecycle.connect":
|
|
102
|
+
self_id = str(data["self_id"])
|
|
103
|
+
if self_id not in self.logins:
|
|
104
|
+
asyncio.create_task(_login_add())
|
|
105
|
+
elif event_type == "meta_event.lifecycle.enable":
|
|
106
|
+
logger.warning(f"received lifecycle.enable event that is only supported in http adapter: {data}")
|
|
107
|
+
return
|
|
108
|
+
elif event_type == "meta_event.lifecycle.disable":
|
|
109
|
+
logger.warning(f"received lifecycle.disable event that is only supported in http adapter: {data}")
|
|
110
|
+
return
|
|
111
|
+
elif event_type == "meta_event.heartbeat":
|
|
112
|
+
self_id = str(data["self_id"])
|
|
113
|
+
if self_id not in self.logins:
|
|
114
|
+
asyncio.create_task(_login_add())
|
|
115
|
+
logger.trace(f"received heartbeat from {self_id}")
|
|
116
|
+
else:
|
|
117
|
+
self_id = str(data["self_id"])
|
|
118
|
+
if self_id not in self.logins:
|
|
119
|
+
logger.warning(f"received event from unknown self_id: {data}")
|
|
98
120
|
return
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return
|
|
123
|
-
login = self.logins[self_id]
|
|
124
|
-
handler = events.get(event_type)
|
|
125
|
-
if not handler:
|
|
126
|
-
event = Event(EventType.INTERNAL, datetime.now(), login)
|
|
127
|
-
else:
|
|
128
|
-
event = await handler(login, self, data)
|
|
129
|
-
if event:
|
|
130
|
-
event._type = event_type
|
|
131
|
-
event._data = data
|
|
132
|
-
await self.server.post(event)
|
|
133
|
-
|
|
134
|
-
asyncio.create_task(event_parse_task(data))
|
|
121
|
+
login = self.logins[self_id]
|
|
122
|
+
handler = events.get(event_type)
|
|
123
|
+
|
|
124
|
+
async def _event_parse(
|
|
125
|
+
_login=login,
|
|
126
|
+
_handler=handler,
|
|
127
|
+
_data=data,
|
|
128
|
+
_event_type=event_type,
|
|
129
|
+
):
|
|
130
|
+
event = None
|
|
131
|
+
if _handler:
|
|
132
|
+
try:
|
|
133
|
+
event = await _handler(_login, self, _data)
|
|
134
|
+
except Exception as e:
|
|
135
|
+
logger.exception(f"failed to handle event {event_type}: {e!r}")
|
|
136
|
+
event = None
|
|
137
|
+
if not event:
|
|
138
|
+
event = Event(EventType.INTERNAL, datetime.now(), _login)
|
|
139
|
+
event._type = _event_type
|
|
140
|
+
event._data = _data
|
|
141
|
+
await self.server.post(event)
|
|
142
|
+
|
|
143
|
+
asyncio.create_task(_event_parse())
|
|
135
144
|
|
|
136
145
|
async def message_receive(self):
|
|
137
146
|
if self.connection is None:
|
|
@@ -85,7 +85,7 @@ class OneBot11MessageEncoder:
|
|
|
85
85
|
},
|
|
86
86
|
)
|
|
87
87
|
if resp:
|
|
88
|
-
self.results.append(MessageObject(resp["message_id"], ""))
|
|
88
|
+
self.results.append(MessageObject(str(resp["message_id"]), ""))
|
|
89
89
|
|
|
90
90
|
async def flush(self):
|
|
91
91
|
if not self.children:
|
|
@@ -111,15 +111,15 @@ class OneBot11MessageEncoder:
|
|
|
111
111
|
|
|
112
112
|
slot = self.stack[0]
|
|
113
113
|
type_, author = slot.type, slot.author
|
|
114
|
-
if not self.children and "
|
|
114
|
+
if not self.children and "messageId" not in author:
|
|
115
115
|
return
|
|
116
116
|
if type_ == "forward":
|
|
117
|
-
if "
|
|
117
|
+
if "messageId" in author:
|
|
118
118
|
self.stack[1].children.append(
|
|
119
119
|
{
|
|
120
120
|
"type": "node",
|
|
121
121
|
"data": {
|
|
122
|
-
"id": author["
|
|
122
|
+
"id": author["messageId"],
|
|
123
123
|
},
|
|
124
124
|
}
|
|
125
125
|
)
|
|
@@ -159,7 +159,7 @@ class OneBot11MessageEncoder:
|
|
|
159
159
|
},
|
|
160
160
|
)
|
|
161
161
|
if resp:
|
|
162
|
-
self.results.append(MessageObject(resp["message_id"], ""))
|
|
162
|
+
self.results.append(MessageObject(str(resp["message_id"]), ""))
|
|
163
163
|
self.children = []
|
|
164
164
|
|
|
165
165
|
async def _send_file(self, attrs: dict[str, Any]):
|
|
@@ -286,7 +286,7 @@ class OneBot11MessageEncoder:
|
|
|
286
286
|
self.stack.pop(0)
|
|
287
287
|
await self.send_forward()
|
|
288
288
|
elif "id" in attrs:
|
|
289
|
-
self.stack[0].author["
|
|
289
|
+
self.stack[0].author["messageId"] = str(attrs["id"])
|
|
290
290
|
else:
|
|
291
291
|
payload = {}
|
|
292
292
|
if "name" in attrs:
|
|
@@ -299,6 +299,8 @@ class OneBot11MessageEncoder:
|
|
|
299
299
|
payload["id"] = int(attrs["id"])
|
|
300
300
|
if "user_id" in attrs:
|
|
301
301
|
payload["id"] = int(attrs["user_id"])
|
|
302
|
+
if "userId" in attrs:
|
|
303
|
+
payload["id"] = int(attrs["userId"])
|
|
302
304
|
if "time" in attrs:
|
|
303
305
|
payload["time"] = int(attrs["time"])
|
|
304
306
|
self.stack[0].author.update(payload)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
from dataclasses import dataclass
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
|
|
6
7
|
from launart import Launart, any_completed
|
|
@@ -44,74 +45,73 @@ class _Connection:
|
|
|
44
45
|
self.close_signal.set()
|
|
45
46
|
|
|
46
47
|
async def message_handle(self):
|
|
48
|
+
async def _login_add():
|
|
49
|
+
self_info = await self.call_api("get_login_info")
|
|
50
|
+
login = Login(
|
|
51
|
+
sn=0,
|
|
52
|
+
status=LoginStatus.ONLINE,
|
|
53
|
+
adapter="onebot",
|
|
54
|
+
platform="qq-client",
|
|
55
|
+
user=User(
|
|
56
|
+
self_id,
|
|
57
|
+
(self_info or {})["nickname"],
|
|
58
|
+
avatar=USER_AVATAR_URL.format(uin=self_id),
|
|
59
|
+
),
|
|
60
|
+
features=["guild.plain"],
|
|
61
|
+
)
|
|
62
|
+
self.adapter.logins[self_id] = login
|
|
63
|
+
await self.adapter.server.post(Event(EventType.LOGIN_ADDED, datetime.now(), login))
|
|
64
|
+
|
|
47
65
|
async for connection, data in self.message_receive():
|
|
48
66
|
if echo := data.get("echo"):
|
|
49
67
|
if future := self.response_waiters.get(echo):
|
|
50
68
|
future.set_result(data)
|
|
51
69
|
continue
|
|
52
70
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
elif event_type == "meta_event.lifecycle.enable":
|
|
74
|
-
logger.warning(f"received lifecycle.enable event that is only supported in http adapter: {data}")
|
|
75
|
-
return
|
|
76
|
-
elif event_type == "meta_event.lifecycle.disable":
|
|
77
|
-
logger.warning(f"received lifecycle.disable event that is only supported in http adapter: {data}")
|
|
71
|
+
event_type = onebot11_event_type(data)
|
|
72
|
+
if event_type == "meta_event.lifecycle.connect":
|
|
73
|
+
self_id = str(data["self_id"])
|
|
74
|
+
if self_id not in self.adapter.logins:
|
|
75
|
+
asyncio.create_task(_login_add())
|
|
76
|
+
elif event_type == "meta_event.lifecycle.enable":
|
|
77
|
+
logger.warning(f"received lifecycle.enable event that is only supported in http adapter: {data}")
|
|
78
|
+
return
|
|
79
|
+
elif event_type == "meta_event.lifecycle.disable":
|
|
80
|
+
logger.warning(f"received lifecycle.disable event that is only supported in http adapter: {data}")
|
|
81
|
+
return
|
|
82
|
+
elif event_type == "meta_event.heartbeat":
|
|
83
|
+
self_id = str(data["self_id"])
|
|
84
|
+
if self_id not in self.adapter.logins:
|
|
85
|
+
asyncio.create_task(_login_add())
|
|
86
|
+
logger.trace(f"received heartbeat from {self_id}")
|
|
87
|
+
else:
|
|
88
|
+
self_id = str(data["self_id"])
|
|
89
|
+
if self_id not in self.adapter.logins:
|
|
90
|
+
logger.warning(f"received event from unknown self_id: {data}")
|
|
78
91
|
return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return
|
|
103
|
-
login = self.adapter.logins[self_id]
|
|
104
|
-
handler = events.get(event_type)
|
|
105
|
-
if not handler:
|
|
106
|
-
event = Event(EventType.INTERNAL, datetime.now(), login)
|
|
107
|
-
else:
|
|
108
|
-
event = await handler(login, self, data)
|
|
109
|
-
if event:
|
|
110
|
-
event._type = event_type
|
|
111
|
-
event._data = data
|
|
112
|
-
await self.adapter.server.post(event)
|
|
113
|
-
|
|
114
|
-
asyncio.create_task(event_parse_task(data))
|
|
92
|
+
login = self.adapter.logins[self_id]
|
|
93
|
+
handler = events.get(event_type)
|
|
94
|
+
|
|
95
|
+
async def _event_parse(
|
|
96
|
+
_login=login,
|
|
97
|
+
_handler=handler,
|
|
98
|
+
_data=data,
|
|
99
|
+
_event_type=event_type,
|
|
100
|
+
):
|
|
101
|
+
event = None
|
|
102
|
+
if _handler:
|
|
103
|
+
try:
|
|
104
|
+
event = await _handler(_login, self, _data)
|
|
105
|
+
except Exception as e:
|
|
106
|
+
logger.exception(f"failed to handle event {_event_type}: {e!r}")
|
|
107
|
+
event = None
|
|
108
|
+
if not event:
|
|
109
|
+
event = Event(EventType.INTERNAL, datetime.now(), _login)
|
|
110
|
+
event._type = _event_type
|
|
111
|
+
event._data = _data
|
|
112
|
+
await self.adapter.server.post(event)
|
|
113
|
+
|
|
114
|
+
asyncio.create_task(_event_parse())
|
|
115
115
|
|
|
116
116
|
async def call_api(self, action: str, params: dict | None = None) -> dict:
|
|
117
117
|
if not self.ws:
|
|
@@ -133,22 +133,33 @@ class _Connection:
|
|
|
133
133
|
return result.get("data", {})
|
|
134
134
|
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
@dataclass
|
|
137
|
+
class OneBot11ReverseConfig:
|
|
138
|
+
prefix: str = "/"
|
|
139
|
+
"""反向适配器于 Server 的路径前缀, 默认为 /"""
|
|
140
|
+
path: str = "onebot/v11"
|
|
141
|
+
"""反向适配器于 Server 的路径, 默认为 onebot/v11"""
|
|
142
|
+
endpoint: str = "ws"
|
|
143
|
+
"""反向适配器于 Server 的路径端点, 默认为 ws (完整路径即为 /onebot/v11/ws)"""
|
|
144
|
+
access_token: str | None = None
|
|
145
|
+
"""反向适配器的访问令牌, 默认为空"""
|
|
146
|
+
timeout: int = 60
|
|
147
|
+
"""发送请求的超时时间,默认为 60 秒"""
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class OneBot11ReverseAdapter(BaseAdapter[OneBot11ReverseConfig]):
|
|
137
151
|
|
|
138
152
|
def __init__(
|
|
139
153
|
self,
|
|
140
|
-
|
|
141
|
-
path: str = "onebot/v11",
|
|
142
|
-
endpoint: str = "ws",
|
|
143
|
-
access_token: str | None = None,
|
|
144
|
-
timeout: int = 60,
|
|
154
|
+
config: OneBot11ReverseConfig,
|
|
145
155
|
):
|
|
146
156
|
super().__init__()
|
|
147
|
-
self.
|
|
148
|
-
self.
|
|
157
|
+
self.config = config
|
|
158
|
+
self.endpoint = URL(config.prefix) / config.path / config.endpoint
|
|
159
|
+
self.access_token = config.access_token
|
|
149
160
|
self.logins: dict[str, Login] = {}
|
|
150
161
|
self.connections: dict[str, _Connection] = {}
|
|
151
|
-
self.timeout = timeout
|
|
162
|
+
self.timeout = config.timeout
|
|
152
163
|
|
|
153
164
|
apply(self, lambda _: self.connections[_], lambda _: self.logins[_])
|
|
154
165
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|