satori-python-core 0.15.2__tar.gz → 0.16.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_core-0.15.2 → satori_python_core-0.16.0}/.mina/core.toml +1 -1
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/PKG-INFO +4 -4
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/README.md +2 -2
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/pyproject.toml +2 -2
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/src/satori/__init__.py +1 -3
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/src/satori/model.py +100 -69
- satori_python_core-0.15.2/src/satori/config.py +0 -67
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/LICENSE +0 -0
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/src/satori/const.py +0 -0
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/src/satori/element.py +0 -0
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/src/satori/event.py +0 -0
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/src/satori/exception.py +0 -0
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/src/satori/parser.py +0 -0
- {satori_python_core-0.15.2 → satori_python_core-0.16.0}/src/satori/utils.py +0 -0
|
@@ -15,7 +15,7 @@ dependencies = [
|
|
|
15
15
|
description = "Satori Protocol SDK for python, specify common part"
|
|
16
16
|
license = {text = "MIT"}
|
|
17
17
|
readme = "README.md"
|
|
18
|
-
requires-python = ">=3.
|
|
18
|
+
requires-python = ">=3.9"
|
|
19
19
|
classifiers = [
|
|
20
20
|
"Typing :: Typed",
|
|
21
21
|
"Development Status :: 4 - Beta",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: satori-python-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.0
|
|
4
4
|
Summary: Satori Protocol SDK for python, specify common part
|
|
5
5
|
Home-page: https://github.com/RF-Tar-Railt/satori-python
|
|
6
6
|
Author-Email: RF-Tar-Railt <rf_tar_railt@qq.com>
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
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
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
20
|
Requires-Dist: loguru>=0.7.2
|
|
21
21
|
Requires-Dist: yarl>=1.9.4
|
|
22
22
|
Requires-Dist: typing-extensions>=4.7.0
|
|
@@ -74,9 +74,9 @@ pip install satori-python-server
|
|
|
74
74
|
客户端:
|
|
75
75
|
|
|
76
76
|
```python
|
|
77
|
-
from satori import EventType
|
|
77
|
+
from satori import EventType
|
|
78
78
|
from satori.event import MessageEvent
|
|
79
|
-
from satori.client import Account, App
|
|
79
|
+
from satori.client import Account, App, WebsocketsInfo
|
|
80
80
|
|
|
81
81
|
app = App(WebsocketsInfo(port=5140))
|
|
82
82
|
|
|
@@ -50,9 +50,9 @@ pip install satori-python-server
|
|
|
50
50
|
客户端:
|
|
51
51
|
|
|
52
52
|
```python
|
|
53
|
-
from satori import EventType
|
|
53
|
+
from satori import EventType
|
|
54
54
|
from satori.event import MessageEvent
|
|
55
|
-
from satori.client import Account, App
|
|
55
|
+
from satori.client import Account, App, WebsocketsInfo
|
|
56
56
|
|
|
57
57
|
app = App(WebsocketsInfo(port=5140))
|
|
58
58
|
|
|
@@ -11,7 +11,7 @@ dependencies = [
|
|
|
11
11
|
]
|
|
12
12
|
description = "Satori Protocol SDK for python, specify common part"
|
|
13
13
|
readme = "README.md"
|
|
14
|
-
requires-python = ">=3.
|
|
14
|
+
requires-python = ">=3.9"
|
|
15
15
|
classifiers = [
|
|
16
16
|
"Typing :: Typed",
|
|
17
17
|
"Development Status :: 4 - Beta",
|
|
@@ -23,7 +23,7 @@ classifiers = [
|
|
|
23
23
|
"Programming Language :: Python :: 3.12",
|
|
24
24
|
"Operating System :: OS Independent",
|
|
25
25
|
]
|
|
26
|
-
version = "0.
|
|
26
|
+
version = "0.16.0"
|
|
27
27
|
|
|
28
28
|
[project.license]
|
|
29
29
|
text = "MIT"
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from .config import WebhookInfo as WebhookInfo
|
|
2
|
-
from .config import WebsocketsInfo as WebsocketsInfo
|
|
3
1
|
from .const import Api as Api
|
|
4
2
|
from .const import EventType as EventType
|
|
5
3
|
from .element import At as At
|
|
@@ -43,4 +41,4 @@ from .model import Role as Role
|
|
|
43
41
|
from .model import Upload as Upload
|
|
44
42
|
from .model import User as User
|
|
45
43
|
|
|
46
|
-
__version__ = "0.
|
|
44
|
+
__version__ = "0.16.0"
|
|
@@ -15,6 +15,7 @@ from .parser import parse
|
|
|
15
15
|
@dataclass
|
|
16
16
|
class ModelBase:
|
|
17
17
|
__converter__: ClassVar[dict[str, Callable[[Any], Any]]] = {}
|
|
18
|
+
_raw_data: dict[str, Any] = field(init=False, default_factory=dict, repr=False, compare=False, hash=False)
|
|
18
19
|
|
|
19
20
|
@classmethod
|
|
20
21
|
def parse(cls, raw: dict):
|
|
@@ -26,7 +27,9 @@ class ModelBase:
|
|
|
26
27
|
data[fd.name] = cls.__converter__[fd.name](raw[fd.name])
|
|
27
28
|
else:
|
|
28
29
|
data[fd.name] = raw[fd.name]
|
|
29
|
-
|
|
30
|
+
obj = cls(**data) # type: ignore
|
|
31
|
+
obj._raw_data = raw
|
|
32
|
+
return obj
|
|
30
33
|
|
|
31
34
|
def dump(self) -> dict:
|
|
32
35
|
raise NotImplementedError
|
|
@@ -129,71 +132,57 @@ class Role(ModelBase):
|
|
|
129
132
|
|
|
130
133
|
class LoginStatus(IntEnum):
|
|
131
134
|
OFFLINE = 0
|
|
135
|
+
"""离线"""
|
|
132
136
|
ONLINE = 1
|
|
137
|
+
"""在线"""
|
|
133
138
|
CONNECT = 2
|
|
139
|
+
"""正在连接"""
|
|
134
140
|
DISCONNECT = 3
|
|
141
|
+
"""正在断开连接"""
|
|
135
142
|
RECONNECT = 4
|
|
143
|
+
"""正在重新连接"""
|
|
136
144
|
|
|
137
145
|
|
|
138
146
|
@dataclass
|
|
139
147
|
class Login(ModelBase):
|
|
148
|
+
sn: str
|
|
140
149
|
status: LoginStatus
|
|
141
|
-
|
|
142
|
-
self_id: Optional[str] = None
|
|
150
|
+
adapter: str
|
|
143
151
|
platform: Optional[str] = None
|
|
152
|
+
user: Optional[User] = None
|
|
144
153
|
features: list[str] = field(default_factory=list)
|
|
145
|
-
proxy_urls: list[str] = field(default_factory=list)
|
|
146
154
|
|
|
147
155
|
__converter__ = {"user": User.parse, "status": LoginStatus}
|
|
148
156
|
|
|
149
157
|
def dump(self):
|
|
150
158
|
res: dict[str, Any] = {
|
|
159
|
+
"sn": self.sn,
|
|
151
160
|
"status": self.status.value,
|
|
152
|
-
"
|
|
153
|
-
"proxy_urls": self.proxy_urls,
|
|
161
|
+
"adapter": self.adapter,
|
|
154
162
|
}
|
|
155
|
-
if self.user:
|
|
156
|
-
res["user"] = self.user.dump()
|
|
157
|
-
if self.self_id:
|
|
158
|
-
res["self_id"] = self.self_id
|
|
159
163
|
if self.platform:
|
|
160
164
|
res["platform"] = self.platform
|
|
165
|
+
if self.user:
|
|
166
|
+
res["user"] = self.user.dump()
|
|
167
|
+
if self.features:
|
|
168
|
+
res["features"] = self.features
|
|
161
169
|
return res
|
|
162
170
|
|
|
163
|
-
@
|
|
164
|
-
def
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
user: User
|
|
171
|
-
platform: str
|
|
172
|
-
status: Optional[LoginStatus] = None
|
|
173
|
-
features: list[str] = field(default_factory=list)
|
|
174
|
-
proxy_urls: list[str] = field(default_factory=list)
|
|
175
|
-
|
|
176
|
-
__converter__ = {"user": User.parse, "status": LoginStatus}
|
|
177
|
-
|
|
178
|
-
def dump(self):
|
|
179
|
-
res: dict[str, Any] = {
|
|
180
|
-
"user": self.user.dump(),
|
|
181
|
-
"platform": self.platform,
|
|
182
|
-
"features": self.features,
|
|
183
|
-
"proxy_urls": self.proxy_urls,
|
|
184
|
-
}
|
|
185
|
-
if self.status:
|
|
186
|
-
res["status"] = self.status.value
|
|
187
|
-
return res
|
|
171
|
+
@classmethod
|
|
172
|
+
def parse(cls, raw: dict):
|
|
173
|
+
if "self_id" in raw and "user" not in raw:
|
|
174
|
+
raw["user"] = {"id": raw["self_id"]}
|
|
175
|
+
if "adapter" not in raw:
|
|
176
|
+
raw["adapter"] = "satori"
|
|
177
|
+
return super().parse(raw)
|
|
188
178
|
|
|
189
179
|
@property
|
|
190
180
|
def id(self) -> str:
|
|
181
|
+
if not self.user:
|
|
182
|
+
raise ValueError(f"Login {self.sn} has not complete yet")
|
|
191
183
|
return self.user.id
|
|
192
184
|
|
|
193
185
|
|
|
194
|
-
LoginType = Union[Login, LoginPreview]
|
|
195
|
-
|
|
196
|
-
|
|
197
186
|
@dataclass
|
|
198
187
|
class ArgvInteraction(ModelBase):
|
|
199
188
|
name: str
|
|
@@ -214,21 +203,70 @@ class ButtonInteraction(ModelBase):
|
|
|
214
203
|
|
|
215
204
|
class Opcode(IntEnum):
|
|
216
205
|
EVENT = 0
|
|
206
|
+
"""事件 (接收)"""
|
|
217
207
|
PING = 1
|
|
208
|
+
"""心跳 (发送)"""
|
|
218
209
|
PONG = 2
|
|
210
|
+
"""心跳回复 (接收)"""
|
|
219
211
|
IDENTIFY = 3
|
|
212
|
+
"""鉴权 (发送)"""
|
|
220
213
|
READY = 4
|
|
214
|
+
"""鉴权成功 (接收)"""
|
|
215
|
+
META = 5
|
|
216
|
+
"""元信息更新 (接收)"""
|
|
221
217
|
|
|
222
218
|
|
|
223
219
|
@dataclass
|
|
224
220
|
class Identify(ModelBase):
|
|
225
221
|
token: Optional[str] = None
|
|
226
|
-
|
|
222
|
+
sn: Optional[int] = None
|
|
223
|
+
|
|
224
|
+
@classmethod
|
|
225
|
+
def parse(cls, raw: dict):
|
|
226
|
+
if "sequence" in raw and "sn" not in raw:
|
|
227
|
+
raw["sn"] = raw["sequence"]
|
|
228
|
+
return super().parse(raw)
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def sequence(self) -> Optional[int]:
|
|
232
|
+
return self.sn
|
|
233
|
+
|
|
234
|
+
def dump(self):
|
|
235
|
+
return asdict(self)
|
|
227
236
|
|
|
228
237
|
|
|
229
238
|
@dataclass
|
|
230
239
|
class Ready(ModelBase):
|
|
231
240
|
logins: list[Login]
|
|
241
|
+
proxy_urls: list[str] = field(default_factory=list)
|
|
242
|
+
|
|
243
|
+
__converter__ = {"logins": lambda raw: [Login.parse(login) for login in raw]}
|
|
244
|
+
|
|
245
|
+
def dump(self):
|
|
246
|
+
return asdict(self)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
@dataclass
|
|
250
|
+
class MetaPayload(ModelBase):
|
|
251
|
+
"""Meta 信令"""
|
|
252
|
+
|
|
253
|
+
proxy_urls: list[str]
|
|
254
|
+
|
|
255
|
+
def dump(self):
|
|
256
|
+
return asdict(self)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@dataclass
|
|
260
|
+
class Meta(ModelBase):
|
|
261
|
+
"""Meta 数据"""
|
|
262
|
+
|
|
263
|
+
logins: list[Login]
|
|
264
|
+
proxy_urls: list[str] = field(default_factory=list)
|
|
265
|
+
|
|
266
|
+
__converter__ = {"logins": lambda raw: [Login.parse(login) for login in raw]}
|
|
267
|
+
|
|
268
|
+
def dump(self):
|
|
269
|
+
return asdict(self)
|
|
232
270
|
|
|
233
271
|
|
|
234
272
|
@dataclass
|
|
@@ -334,16 +372,13 @@ class MessageReceipt(ModelBase):
|
|
|
334
372
|
|
|
335
373
|
@dataclass
|
|
336
374
|
class Event(ModelBase):
|
|
337
|
-
id: int
|
|
338
375
|
type: str
|
|
339
376
|
timestamp: datetime
|
|
340
|
-
|
|
341
|
-
self_id: Optional[str] = None
|
|
377
|
+
login: Login
|
|
342
378
|
argv: Optional[ArgvInteraction] = None
|
|
343
379
|
button: Optional[ButtonInteraction] = None
|
|
344
380
|
channel: Optional[Channel] = None
|
|
345
381
|
guild: Optional[Guild] = None
|
|
346
|
-
login: Optional[LoginType] = None
|
|
347
382
|
member: Optional[Member] = None
|
|
348
383
|
message: Optional[MessageObject] = None
|
|
349
384
|
operator: Optional[User] = None
|
|
@@ -353,19 +388,15 @@ class Event(ModelBase):
|
|
|
353
388
|
_type: Optional[str] = None
|
|
354
389
|
_data: Optional[dict] = None
|
|
355
390
|
|
|
391
|
+
sn: int = 0
|
|
392
|
+
|
|
356
393
|
__converter__ = {
|
|
357
394
|
"timestamp": lambda ts: datetime.fromtimestamp(int(ts) / 1000),
|
|
358
395
|
"argv": ArgvInteraction.parse,
|
|
359
396
|
"button": ButtonInteraction.parse,
|
|
360
397
|
"channel": Channel.parse,
|
|
361
398
|
"guild": Guild.parse,
|
|
362
|
-
"login":
|
|
363
|
-
LoginPreview.parse(
|
|
364
|
-
raw if raw["user"] else {**raw, "user": {"id": raw["self_id"]}} if "self_id" in raw else raw
|
|
365
|
-
)
|
|
366
|
-
if "user" in raw
|
|
367
|
-
else Login.parse(raw)
|
|
368
|
-
),
|
|
399
|
+
"login": Login.parse,
|
|
369
400
|
"member": Member.parse,
|
|
370
401
|
"message": MessageObject.parse,
|
|
371
402
|
"operator": User.parse,
|
|
@@ -373,33 +404,33 @@ class Event(ModelBase):
|
|
|
373
404
|
"user": User.parse,
|
|
374
405
|
}
|
|
375
406
|
|
|
376
|
-
@
|
|
377
|
-
def
|
|
378
|
-
if
|
|
379
|
-
|
|
380
|
-
if
|
|
381
|
-
|
|
382
|
-
|
|
407
|
+
@classmethod
|
|
408
|
+
def parse(cls, raw: dict):
|
|
409
|
+
if "id" in raw and "sn" not in raw:
|
|
410
|
+
raw["sn"] = raw["id"]
|
|
411
|
+
if "platform" in raw and "self_id" in raw and "login" not in raw:
|
|
412
|
+
raw["login"] = {
|
|
413
|
+
"sn": raw["self_id"],
|
|
414
|
+
"platform": raw["platform"],
|
|
415
|
+
"user": {"id": raw["self_id"]},
|
|
416
|
+
"status": LoginStatus.ONLINE,
|
|
417
|
+
}
|
|
418
|
+
return super().parse(raw)
|
|
383
419
|
|
|
384
420
|
@property
|
|
385
|
-
def
|
|
386
|
-
|
|
387
|
-
return self.self_id
|
|
388
|
-
if self.login and self.login.id:
|
|
389
|
-
return self.login.id
|
|
390
|
-
raise ValueError("self_id not found")
|
|
421
|
+
def platform(self):
|
|
422
|
+
return self.login.platform
|
|
391
423
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
424
|
+
@property
|
|
425
|
+
def self_id(self):
|
|
426
|
+
return self.login.id
|
|
395
427
|
|
|
396
428
|
def dump(self):
|
|
397
429
|
res = {
|
|
398
|
-
"
|
|
430
|
+
"sn": self.sn,
|
|
399
431
|
"type": self.type,
|
|
400
|
-
"platform": self.platform_,
|
|
401
|
-
"self_id": self.self_id_,
|
|
402
432
|
"timestamp": int(self.timestamp.timestamp() * 1000),
|
|
433
|
+
"login": self.login.dump(),
|
|
403
434
|
}
|
|
404
435
|
if self.argv:
|
|
405
436
|
res["argv"] = self.argv.dump()
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from yarl import URL
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Config:
|
|
8
|
-
@property
|
|
9
|
-
def identity(self) -> str:
|
|
10
|
-
raise NotImplementedError
|
|
11
|
-
|
|
12
|
-
@property
|
|
13
|
-
def token(self) -> Optional[str]:
|
|
14
|
-
raise NotImplementedError
|
|
15
|
-
|
|
16
|
-
@property
|
|
17
|
-
def api_base(self) -> URL:
|
|
18
|
-
raise NotImplementedError
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@dataclass
|
|
22
|
-
class WebsocketsInfo(Config):
|
|
23
|
-
host: str = "localhost"
|
|
24
|
-
port: int = 5140
|
|
25
|
-
path: str = ""
|
|
26
|
-
token: Optional[str] = None
|
|
27
|
-
|
|
28
|
-
def __post_init__(self):
|
|
29
|
-
if self.path and not self.path.startswith("/"):
|
|
30
|
-
self.path = f"/{self.path}"
|
|
31
|
-
|
|
32
|
-
@property
|
|
33
|
-
def identity(self):
|
|
34
|
-
return f"{self.host}:{self.port}"
|
|
35
|
-
|
|
36
|
-
@property
|
|
37
|
-
def api_base(self):
|
|
38
|
-
return URL(f"http://{self.host}:{self.port}{self.path}") / "v1"
|
|
39
|
-
|
|
40
|
-
@property
|
|
41
|
-
def ws_base(self):
|
|
42
|
-
return URL(f"ws://{self.host}:{self.port}{self.path}") / "v1"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@dataclass
|
|
46
|
-
class WebhookInfo(Config):
|
|
47
|
-
host: str = "127.0.0.1"
|
|
48
|
-
port: int = 8080
|
|
49
|
-
path: str = "v1/events"
|
|
50
|
-
token: Optional[str] = None
|
|
51
|
-
server_host: str = "localhost"
|
|
52
|
-
server_port: int = 5140
|
|
53
|
-
server_path: str = ""
|
|
54
|
-
|
|
55
|
-
def __post_init__(self):
|
|
56
|
-
if self.path and not self.path.startswith("/"):
|
|
57
|
-
self.path = f"/{self.path}"
|
|
58
|
-
if self.server_path and not self.server_path.startswith("/"):
|
|
59
|
-
self.server_path = f"/{self.server_path}"
|
|
60
|
-
|
|
61
|
-
@property
|
|
62
|
-
def identity(self):
|
|
63
|
-
return f"{self.host}:{self.port}{self.path}"
|
|
64
|
-
|
|
65
|
-
@property
|
|
66
|
-
def api_base(self):
|
|
67
|
-
return URL(f"http://{self.server_host}:{self.server_port}{self.server_path}") / "v1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|