satori-python-adapter-milky 0.4.2__tar.gz → 0.5.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.
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/.mina/adapter_milky.toml +2 -2
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/PKG-INFO +2 -2
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/pyproject.toml +2 -2
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/__init__.py +2 -2
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/base.py +34 -15
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/events/base.py +1 -1
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/main.py +5 -10
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/message.py +25 -7
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/sse.py +5 -10
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/webhook.py +17 -13
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/LICENSE +0 -0
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/README.md +0 -0
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/api.py +0 -0
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/events/__init__.py +0 -0
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/events/group.py +0 -0
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/events/message.py +0 -0
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/events/request.py +0 -0
- {satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/src/satori/adapters/milky/utils.py +0 -0
{satori_python_adapter_milky-0.4.2 → satori_python_adapter_milky-0.5.0}/.mina/adapter_milky.toml
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
includes = ["src/satori/adapters/milky"]
|
|
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-milky"
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.5.0"
|
|
7
7
|
authors = [
|
|
8
8
|
{name = "RF-Tar-Railt", email = "rf_tar_railt@qq.com"}
|
|
9
9
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: satori-python-adapter-milky
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Satori Protocol SDK for python, adapter for Milky
|
|
5
5
|
Home-page: https://github.com/RF-Tar-Railt/satori-python
|
|
6
6
|
Author-Email: RF-Tar-Railt <rf_tar_railt@qq.com>
|
|
@@ -17,7 +17,7 @@ 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
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "satori-python-adapter-milky"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
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 Milky"
|
|
11
11
|
readme = "README.md"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
from .base import MilkyBaseConfig as MilkyBaseConfig
|
|
1
2
|
from .main import MilkyWebsocketAdapter as MilkyWebsocketAdapter
|
|
2
3
|
from .sse import MilkySSEAdapter as MilkySSEAdapter
|
|
3
4
|
from .webhook import MilkyWebhookAdapter as MilkyWebhookAdapter
|
|
4
|
-
|
|
5
|
-
__all__ = ["MilkyWebsocketAdapter", "MilkySSEAdapter", "MilkyWebhookAdapter"]
|
|
5
|
+
from .webhook import MilkyWebhookConfig as MilkyWebhookConfig
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from abc import ABC
|
|
4
|
+
from dataclasses import dataclass, field
|
|
4
5
|
from datetime import datetime
|
|
6
|
+
from typing_extensions import TypeVar
|
|
5
7
|
|
|
6
8
|
import aiohttp
|
|
7
9
|
from launart.status import Phase
|
|
@@ -23,24 +25,37 @@ from .utils import decode_login_user
|
|
|
23
25
|
DEFAULT_FEATURES = ["guild.plain", "reaction"]
|
|
24
26
|
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
@dataclass
|
|
29
|
+
class MilkyBaseConfig:
|
|
30
|
+
endpoint: str
|
|
31
|
+
"""连接 Milky 协议端的路径"""
|
|
32
|
+
token: str | None = None
|
|
33
|
+
"""Milky 协议的访问令牌, 默认为空"""
|
|
34
|
+
token_in_query: bool = False
|
|
35
|
+
"""是否将 token 放在查询参数中, 默认为 False"""
|
|
36
|
+
headers: dict[str, str] = field(default_factory=dict)
|
|
37
|
+
"""连接时使用的自定义请求头, 默认为空字典"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
TMilkyBaseConfig = TypeVar("TMilkyBaseConfig", bound=MilkyBaseConfig, default=MilkyBaseConfig)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class MilkyBaseAdapter(BaseAdapter[TMilkyBaseConfig], ABC):
|
|
27
44
|
"""Base adapter for Milky protocol with common functionality."""
|
|
28
45
|
|
|
29
46
|
session: aiohttp.ClientSession | None
|
|
30
47
|
|
|
31
48
|
def __init__(
|
|
32
49
|
self,
|
|
33
|
-
|
|
34
|
-
*,
|
|
35
|
-
token: str | None = None,
|
|
36
|
-
headers: dict[str, str] | None = None,
|
|
50
|
+
config: TMilkyBaseConfig,
|
|
37
51
|
):
|
|
38
52
|
super().__init__()
|
|
39
|
-
self.
|
|
53
|
+
self.config = config
|
|
54
|
+
self.base_url = URL(self.config.endpoint)
|
|
40
55
|
base_path = self.base_url.path.rstrip("/")
|
|
41
56
|
self.api_base = self.base_url.with_path(f"{base_path}/api")
|
|
42
|
-
self.token = token
|
|
43
|
-
self.headers = headers.copy()
|
|
57
|
+
self.token = config.token
|
|
58
|
+
self.headers = config.headers.copy()
|
|
44
59
|
self.session = None
|
|
45
60
|
self.logins: dict[str, Login] = {}
|
|
46
61
|
self.features: list[str] = list(DEFAULT_FEATURES)
|
|
@@ -110,18 +125,22 @@ class MilkyBaseAdapter(BaseAdapter, ABC):
|
|
|
110
125
|
return
|
|
111
126
|
login = self.logins[self_id]
|
|
112
127
|
handler = event_handlers.get(event_type)
|
|
128
|
+
event = None
|
|
113
129
|
if handler:
|
|
114
|
-
|
|
115
|
-
|
|
130
|
+
try:
|
|
131
|
+
event = await handler(login, self, payload)
|
|
132
|
+
except Exception as e:
|
|
133
|
+
logger.exception(f"failed to handle event {event_type}: {e!r}")
|
|
134
|
+
event = None
|
|
135
|
+
if not event:
|
|
116
136
|
event = Event(
|
|
117
137
|
EventType.INTERNAL,
|
|
118
138
|
datetime.fromtimestamp(payload.get("time", datetime.now().timestamp())),
|
|
119
139
|
login,
|
|
120
140
|
)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
await self.server.post(event)
|
|
141
|
+
event._type = event_type
|
|
142
|
+
event._data = payload.get("data", {})
|
|
143
|
+
await self.server.post(event)
|
|
125
144
|
|
|
126
145
|
async def refresh_login(self):
|
|
127
146
|
try:
|
|
@@ -151,4 +170,4 @@ class MilkyBaseAdapter(BaseAdapter, ABC):
|
|
|
151
170
|
return self.logins[self_id]
|
|
152
171
|
|
|
153
172
|
|
|
154
|
-
__all__ = ["MilkyBaseAdapter", "DEFAULT_FEATURES"]
|
|
173
|
+
__all__ = ["MilkyBaseAdapter", "DEFAULT_FEATURES", "MilkyBaseConfig"]
|
|
@@ -5,11 +5,10 @@ import asyncio
|
|
|
5
5
|
import aiohttp
|
|
6
6
|
from launart import Launart, any_completed
|
|
7
7
|
from loguru import logger
|
|
8
|
-
from yarl import URL
|
|
9
8
|
|
|
10
9
|
from satori.utils import decode
|
|
11
10
|
|
|
12
|
-
from .base import MilkyBaseAdapter
|
|
11
|
+
from .base import MilkyBaseAdapter, MilkyBaseConfig
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class MilkyWebsocketAdapter(MilkyBaseAdapter):
|
|
@@ -18,18 +17,14 @@ class MilkyWebsocketAdapter(MilkyBaseAdapter):
|
|
|
18
17
|
|
|
19
18
|
def __init__(
|
|
20
19
|
self,
|
|
21
|
-
|
|
22
|
-
*,
|
|
23
|
-
token: str | None = None,
|
|
24
|
-
token_in_query: bool = False,
|
|
25
|
-
headers: dict[str, str] | None = None,
|
|
20
|
+
config: MilkyBaseConfig,
|
|
26
21
|
):
|
|
27
|
-
super().__init__(
|
|
22
|
+
super().__init__(config)
|
|
28
23
|
base_path = self.base_url.path.rstrip("/")
|
|
29
24
|
ws_scheme = "wss" if self.base_url.scheme == "https" else "ws"
|
|
30
25
|
self.event_url = self.base_url.with_scheme(ws_scheme).with_path(f"{base_path}/event")
|
|
31
|
-
if token_in_query and token:
|
|
32
|
-
self.event_url = self.event_url.update_query(access_token=token)
|
|
26
|
+
if config.token_in_query and self.token:
|
|
27
|
+
self.event_url = self.event_url.update_query(access_token=self.token)
|
|
33
28
|
self.connection = None
|
|
34
29
|
self.close_signal = asyncio.Event()
|
|
35
30
|
|
|
@@ -6,6 +6,8 @@ from dataclasses import dataclass, field
|
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
from typing import Any, Literal
|
|
8
8
|
|
|
9
|
+
from loguru import logger
|
|
10
|
+
|
|
9
11
|
from satori.element import Custom, E, Element
|
|
10
12
|
from satori.model import Channel, ChannelType, Login, MessageObject, User
|
|
11
13
|
from satori.parser import Element as RawElement
|
|
@@ -138,7 +140,10 @@ class MilkyMessageEncoder:
|
|
|
138
140
|
if match := _BASE64_RE.match(uri):
|
|
139
141
|
uri = f"base64://{uri[len(match.group(0)) :]}"
|
|
140
142
|
self.segments.append(
|
|
141
|
-
{
|
|
143
|
+
{
|
|
144
|
+
"type": "image",
|
|
145
|
+
"data": {"uri": uri, "sub_type": attrs.get("sub_type", attrs.get("subTyoe", "normal"))},
|
|
146
|
+
}
|
|
142
147
|
)
|
|
143
148
|
case "audio":
|
|
144
149
|
uri = attrs.get("src") or attrs.get("url")
|
|
@@ -169,7 +174,9 @@ class MilkyMessageEncoder:
|
|
|
169
174
|
await self._send_file(attrs)
|
|
170
175
|
case "milky:light_app":
|
|
171
176
|
await self.flush()
|
|
172
|
-
self.segments.append(
|
|
177
|
+
self.segments.append(
|
|
178
|
+
{"type": "light_app", "data": {"json_payload": attrs.get("json_payload", attrs["jsonPayload"])}}
|
|
179
|
+
)
|
|
173
180
|
case "author":
|
|
174
181
|
self.stack[0].author.update(attrs)
|
|
175
182
|
case "quote":
|
|
@@ -196,7 +203,7 @@ class MilkyMessageEncoder:
|
|
|
196
203
|
if "id" in attrs:
|
|
197
204
|
payload["id"] = int(attrs["id"])
|
|
198
205
|
if "user_id" in attrs:
|
|
199
|
-
payload["id"] = int(attrs
|
|
206
|
+
payload["id"] = int(attrs.get("user_id", attrs["userId"]))
|
|
200
207
|
if "time" in attrs:
|
|
201
208
|
payload["time"] = int(attrs["time"])
|
|
202
209
|
self.stack[0].author.update(payload)
|
|
@@ -389,7 +396,15 @@ async def _decode_segments(net: MilkyNetwork, payload: dict, segments: Sequence[
|
|
|
389
396
|
case "forward":
|
|
390
397
|
forward_id = data.get("forward_id")
|
|
391
398
|
if forward_id is not None:
|
|
392
|
-
|
|
399
|
+
try:
|
|
400
|
+
messages = (await net.call_api("get_forwarded_messages", {"forward_id": forward_id}))[
|
|
401
|
+
"messages"
|
|
402
|
+
]
|
|
403
|
+
except Exception as e:
|
|
404
|
+
logger.error(
|
|
405
|
+
f"Failed to fetch forwarded messages for forward_id {forward_id}: {payload}", exc_info=e
|
|
406
|
+
)
|
|
407
|
+
messages = []
|
|
393
408
|
forward_elements = []
|
|
394
409
|
for msg in messages:
|
|
395
410
|
sender_name = msg.get("sender_name")
|
|
@@ -405,7 +420,10 @@ async def _decode_segments(net: MilkyNetwork, payload: dict, segments: Sequence[
|
|
|
405
420
|
"message_seq": msg["message_seq"],
|
|
406
421
|
},
|
|
407
422
|
)
|
|
408
|
-
except Exception:
|
|
423
|
+
except Exception as e:
|
|
424
|
+
logger.error(
|
|
425
|
+
f"Failed to fetch message {msg['message_seq']} for forward: {payload}", exc_info=e
|
|
426
|
+
)
|
|
409
427
|
pass
|
|
410
428
|
if response:
|
|
411
429
|
origin = await decode_message(net, response["message"])
|
|
@@ -417,7 +435,6 @@ async def _decode_segments(net: MilkyNetwork, payload: dict, segments: Sequence[
|
|
|
417
435
|
)
|
|
418
436
|
)
|
|
419
437
|
content.extend(origin.message)
|
|
420
|
-
|
|
421
438
|
else:
|
|
422
439
|
content = await _decode_segments(net, payload, msg.get("segments", []))
|
|
423
440
|
content.insert(0, E.author(str(msg.get("sender_id")), sender_name, avatar))
|
|
@@ -446,7 +463,8 @@ async def _decode_reply(net: MilkyNetwork, payload: dict, data: dict, message_se
|
|
|
446
463
|
"message_seq": message_seq,
|
|
447
464
|
},
|
|
448
465
|
)
|
|
449
|
-
except Exception:
|
|
466
|
+
except Exception as e:
|
|
467
|
+
logger.error(f"Failed to fetch message {message_seq} for reply: {payload}", exc_info=e)
|
|
450
468
|
return None
|
|
451
469
|
if not response or "message" not in response:
|
|
452
470
|
return None
|
|
@@ -5,28 +5,23 @@ import asyncio
|
|
|
5
5
|
import aiohttp
|
|
6
6
|
from launart import Launart, any_completed
|
|
7
7
|
from loguru import logger
|
|
8
|
-
from yarl import URL
|
|
9
8
|
|
|
10
9
|
from satori.utils import decode
|
|
11
10
|
|
|
12
|
-
from .base import MilkyBaseAdapter
|
|
11
|
+
from .base import MilkyBaseAdapter, MilkyBaseConfig
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class MilkySSEAdapter(MilkyBaseAdapter):
|
|
16
15
|
|
|
17
16
|
def __init__(
|
|
18
17
|
self,
|
|
19
|
-
|
|
20
|
-
*,
|
|
21
|
-
token: str | None = None,
|
|
22
|
-
token_in_query: bool = False,
|
|
23
|
-
headers: dict[str, str] | None = None,
|
|
18
|
+
config: MilkyBaseConfig,
|
|
24
19
|
):
|
|
25
|
-
super().__init__(
|
|
20
|
+
super().__init__(config)
|
|
26
21
|
base_path = self.base_url.path.rstrip("/")
|
|
27
22
|
self.event_url = self.base_url.with_path(f"{base_path}/event")
|
|
28
|
-
if token_in_query and token:
|
|
29
|
-
self.event_url = self.event_url.update_query(access_token=token)
|
|
23
|
+
if config.token_in_query and self.token:
|
|
24
|
+
self.event_url = self.event_url.update_query(access_token=self.token)
|
|
30
25
|
self.close_signal = asyncio.Event()
|
|
31
26
|
|
|
32
27
|
async def launch(self, manager: Launart):
|
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
3
5
|
import aiohttp
|
|
4
6
|
from launart import Launart
|
|
5
7
|
from loguru import logger
|
|
6
8
|
from starlette.requests import Request as StarletteRequest
|
|
7
9
|
from starlette.responses import JSONResponse, Response
|
|
8
10
|
from starlette.routing import Route
|
|
9
|
-
from yarl import URL
|
|
10
11
|
|
|
11
|
-
from .base import MilkyBaseAdapter
|
|
12
|
+
from .base import MilkyBaseAdapter, MilkyBaseConfig
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class MilkyWebhookConfig(MilkyBaseConfig):
|
|
17
|
+
path: str = "/milky"
|
|
18
|
+
"""Webhook 适配器于 Server 的路径, 默认为 /milky"""
|
|
19
|
+
self_token: str | None = None
|
|
20
|
+
"""Webhook 适配器的自定义访问令牌, 默认为 None, 若未设置则使用 Milky 协议的 token"""
|
|
12
21
|
|
|
13
22
|
|
|
14
|
-
class MilkyWebhookAdapter(MilkyBaseAdapter):
|
|
23
|
+
class MilkyWebhookAdapter(MilkyBaseAdapter[MilkyWebhookConfig]):
|
|
15
24
|
|
|
16
25
|
def __init__(
|
|
17
26
|
self,
|
|
18
|
-
|
|
19
|
-
*,
|
|
20
|
-
token: str | None = None,
|
|
21
|
-
headers: dict[str, str] | None = None,
|
|
22
|
-
path: str = "/milky",
|
|
23
|
-
self_token: str | None = None,
|
|
27
|
+
config: MilkyWebhookConfig,
|
|
24
28
|
):
|
|
25
|
-
super().__init__(
|
|
26
|
-
self.webhook_token = self_token if self_token is not None else token
|
|
27
|
-
self.webhook_paths = self._normalize_webhook_paths(path)
|
|
29
|
+
super().__init__(config)
|
|
30
|
+
self.webhook_token = config.self_token if config.self_token is not None else config.token
|
|
31
|
+
self.webhook_paths = self._normalize_webhook_paths(config.path)
|
|
28
32
|
|
|
29
33
|
async def launch(self, manager: Launart):
|
|
30
34
|
async with self.stage("preparing"):
|
|
@@ -79,4 +83,4 @@ class MilkyWebhookAdapter(MilkyBaseAdapter):
|
|
|
79
83
|
return Response(status_code=204)
|
|
80
84
|
|
|
81
85
|
|
|
82
|
-
__all__ = ["MilkyWebhookAdapter"]
|
|
86
|
+
__all__ = ["MilkyWebhookAdapter", "MilkyWebhookConfig"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|