satori-python-server 0.15.0rc2__tar.gz → 0.15.2__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_server-0.15.0rc2 → satori_python_server-0.15.2}/.mina/server.toml +1 -1
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/PKG-INFO +3 -2
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/README.md +1 -0
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/pyproject.toml +5 -2
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/__init__.py +26 -12
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/adapter.py +6 -4
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/model.py +2 -2
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/LICENSE +0 -0
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/conection.py +0 -0
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/formdata.py +0 -0
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/route.py +0 -0
- {satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: satori-python-server
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.2
|
|
4
4
|
Summary: Satori Protocol SDK for python, specify server 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>
|
|
@@ -23,7 +23,7 @@ Requires-Dist: graia-amnesia>=0.9.0
|
|
|
23
23
|
Requires-Dist: starlette[python-multipart]>=0.37.2
|
|
24
24
|
Requires-Dist: uvicorn[standard]>=0.28.0
|
|
25
25
|
Requires-Dist: python-multipart>=0.0.9
|
|
26
|
-
Requires-Dist: satori-python-core>=0.
|
|
26
|
+
Requires-Dist: satori-python-core>=0.15.0
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
|
|
29
29
|
# satori-python
|
|
@@ -44,6 +44,7 @@ Description-Content-Type: text/markdown
|
|
|
44
44
|
目前提供了 `satori` 协议实现的有:
|
|
45
45
|
|
|
46
46
|
- [Chronocat](https://chronocat.vercel.app)
|
|
47
|
+
- [nekobox](https://github.com/wyapx/nekobox)
|
|
47
48
|
- Koishi (搭配 `@koishijs/plugin-server`)
|
|
48
49
|
|
|
49
50
|
### 使用该 SDK 的框架
|
|
@@ -11,7 +11,7 @@ dependencies = [
|
|
|
11
11
|
"starlette[python-multipart]>=0.37.2",
|
|
12
12
|
"uvicorn[standard]>=0.28.0",
|
|
13
13
|
"python-multipart>=0.0.9",
|
|
14
|
-
"satori-python-core >= 0.
|
|
14
|
+
"satori-python-core >= 0.15.0",
|
|
15
15
|
]
|
|
16
16
|
description = "Satori Protocol SDK for python, specify server part"
|
|
17
17
|
readme = "README.md"
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
"Programming Language :: Python :: 3.12",
|
|
28
28
|
"Operating System :: OS Independent",
|
|
29
29
|
]
|
|
30
|
-
version = "0.15.
|
|
30
|
+
version = "0.15.2"
|
|
31
31
|
|
|
32
32
|
[project.license]
|
|
33
33
|
text = "MIT"
|
|
@@ -59,6 +59,9 @@ includes = [
|
|
|
59
59
|
"src/satori/server",
|
|
60
60
|
".mina/server.toml",
|
|
61
61
|
]
|
|
62
|
+
excludes = [
|
|
63
|
+
"src/satori/adapters/*",
|
|
64
|
+
]
|
|
62
65
|
|
|
63
66
|
[tool.pdm.scripts.format]
|
|
64
67
|
composite = [
|
{satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/__init__.py
RENAMED
|
@@ -9,6 +9,7 @@ import threading
|
|
|
9
9
|
import urllib.parse
|
|
10
10
|
from collections.abc import Iterable
|
|
11
11
|
from contextlib import suppress
|
|
12
|
+
from itertools import chain
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
from tempfile import TemporaryDirectory
|
|
14
15
|
from traceback import print_exc
|
|
@@ -43,7 +44,9 @@ from .route import RouterMixin as RouterMixin
|
|
|
43
44
|
from .utils import Deque
|
|
44
45
|
|
|
45
46
|
|
|
46
|
-
async def _request_handler(
|
|
47
|
+
async def _request_handler(
|
|
48
|
+
method: str, request: StarletteRequest, func: RouteCall, platform: str, self_id: str
|
|
49
|
+
):
|
|
47
50
|
if method == Api.UPLOAD_CREATE.value:
|
|
48
51
|
async with request.form() as form:
|
|
49
52
|
res = await func(
|
|
@@ -51,16 +54,24 @@ async def _request_handler(method: str, request: StarletteRequest, func: RouteCa
|
|
|
51
54
|
cast(dict, request.headers.mutablecopy()),
|
|
52
55
|
method,
|
|
53
56
|
form,
|
|
57
|
+
platform=platform,
|
|
58
|
+
self_id=self_id,
|
|
54
59
|
)
|
|
55
60
|
)
|
|
56
61
|
return JSONResponse(content=res)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
try:
|
|
63
|
+
res = await func(
|
|
64
|
+
Request(
|
|
65
|
+
cast(dict, request.headers.mutablecopy()),
|
|
66
|
+
method,
|
|
67
|
+
await request.json(),
|
|
68
|
+
platform=platform,
|
|
69
|
+
self_id=self_id,
|
|
70
|
+
)
|
|
62
71
|
)
|
|
63
|
-
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.error(e)
|
|
74
|
+
return Response(status_code=500, content=str(e))
|
|
64
75
|
if isinstance(res, ModelBase):
|
|
65
76
|
return JSONResponse(content=res.dump())
|
|
66
77
|
if res and isinstance(res, list) and isinstance(res[0], ModelBase):
|
|
@@ -86,6 +97,7 @@ class Server(Service, RouterMixin):
|
|
|
86
97
|
port: int = 5140,
|
|
87
98
|
path: str = "",
|
|
88
99
|
version: str = "v1",
|
|
100
|
+
token: str | None = None,
|
|
89
101
|
webhooks: list[WebhookInfo] | None = None,
|
|
90
102
|
stream_threshold: int = 16 * 1024 * 1024,
|
|
91
103
|
stream_chunk_size: int = 64 * 1024,
|
|
@@ -98,6 +110,7 @@ class Server(Service, RouterMixin):
|
|
|
98
110
|
if self.path and not self.path.startswith("/"):
|
|
99
111
|
self.path = f"/{self.path}"
|
|
100
112
|
self.url_base = f"http://{host}:{port}{self.path}/{version}"
|
|
113
|
+
self.token = token
|
|
101
114
|
self._adapters = []
|
|
102
115
|
self.providers = []
|
|
103
116
|
self.routers = []
|
|
@@ -167,9 +180,9 @@ class Server(Service, RouterMixin):
|
|
|
167
180
|
body = identity["body"]
|
|
168
181
|
token = identity["body"].get("token")
|
|
169
182
|
logins = []
|
|
183
|
+
if token != self.token:
|
|
184
|
+
return await ws.close(code=3000, reason="Unauthorized")
|
|
170
185
|
for provider in self.providers:
|
|
171
|
-
if not provider.authenticate(token):
|
|
172
|
-
return await ws.close(code=3000, reason="Unauthorized")
|
|
173
186
|
_logins = await provider.get_logins()
|
|
174
187
|
for _login in _logins:
|
|
175
188
|
_login.proxy_urls.extend(provider.proxy_urls())
|
|
@@ -220,13 +233,13 @@ class Server(Service, RouterMixin):
|
|
|
220
233
|
continue
|
|
221
234
|
if not _router.ensure(platform, self_id):
|
|
222
235
|
continue
|
|
223
|
-
return await _request_handler(method, request, _router.routes[method])
|
|
236
|
+
return await _request_handler(method, request, _router.routes[method], platform, self_id)
|
|
224
237
|
if method in self.routes:
|
|
225
|
-
return await _request_handler(method, request, self.routes[method])
|
|
238
|
+
return await _request_handler(method, request, self.routes[method], platform, self_id)
|
|
226
239
|
for _router in self.routers:
|
|
227
240
|
if method not in _router.routes:
|
|
228
241
|
continue
|
|
229
|
-
return await _request_handler(method, request, _router.routes[method])
|
|
242
|
+
return await _request_handler(method, request, _router.routes[method], platform, self_id)
|
|
230
243
|
return Response(status_code=404, content=method)
|
|
231
244
|
|
|
232
245
|
async def proxy_url_handler(self, request: StarletteRequest):
|
|
@@ -322,6 +335,7 @@ class Server(Service, RouterMixin):
|
|
|
322
335
|
asgi_service = manager.get_component(UvicornASGIService)
|
|
323
336
|
app = Starlette(
|
|
324
337
|
routes=[
|
|
338
|
+
*chain.from_iterable(ada.get_routes() for ada in self._adapters),
|
|
325
339
|
WebSocketRoute(f"{self.path}/{self.version}/events", self.websocket_server_handler),
|
|
326
340
|
Route(
|
|
327
341
|
f"{self.path}/{self.version}/admin/login.list",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
from collections.abc import AsyncIterator
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from launart import Service
|
|
6
|
+
from starlette.routing import BaseRoute
|
|
6
7
|
|
|
7
8
|
from ..model import Event, LoginType
|
|
8
9
|
from .route import RouterMixin
|
|
@@ -24,9 +25,6 @@ class Adapter(Service, RouterMixin):
|
|
|
24
25
|
@abstractmethod
|
|
25
26
|
def ensure(self, platform: str, self_id: str) -> bool: ...
|
|
26
27
|
|
|
27
|
-
@abstractmethod
|
|
28
|
-
def authenticate(self, token: Optional[str]) -> bool: ...
|
|
29
|
-
|
|
30
28
|
@staticmethod
|
|
31
29
|
def proxy_urls() -> list[str]:
|
|
32
30
|
return []
|
|
@@ -51,3 +49,7 @@ class Adapter(Service, RouterMixin):
|
|
|
51
49
|
|
|
52
50
|
def ensure_server(self, server: "Server"):
|
|
53
51
|
self.server = server
|
|
52
|
+
|
|
53
|
+
def get_routes(self) -> list[BaseRoute]:
|
|
54
|
+
"""return extra routes that will mount to the server root"""
|
|
55
|
+
return []
|
|
@@ -18,14 +18,14 @@ class Request(Generic[TP]):
|
|
|
18
18
|
headers: dict[str, Any]
|
|
19
19
|
action: str
|
|
20
20
|
params: TP
|
|
21
|
+
platform: str
|
|
22
|
+
self_id: str
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
@runtime_checkable
|
|
24
26
|
class Provider(Protocol):
|
|
25
27
|
def publisher(self) -> AsyncIterator[Event]: ...
|
|
26
28
|
|
|
27
|
-
def authenticate(self, token: Optional[str]) -> bool: ...
|
|
28
|
-
|
|
29
29
|
async def get_logins(self) -> Union[list[Login], list[LoginPreview], list[LoginType]]: ...
|
|
30
30
|
|
|
31
31
|
@staticmethod
|
|
File without changes
|
{satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/conection.py
RENAMED
|
File without changes
|
{satori_python_server-0.15.0rc2 → satori_python_server-0.15.2}/src/satori/server/formdata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|