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.
@@ -1,5 +1,5 @@
1
1
  includes = ["src/satori/server"]
2
- raw-dependencies = ["satori-python-core >= 0.11.4"]
2
+ raw-dependencies = ["satori-python-core >= 0.15.0"]
3
3
 
4
4
  [project]
5
5
  name = "satori-python-server"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: satori-python-server
3
- Version: 0.15.0rc2
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.11.4
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 的框架
@@ -16,6 +16,7 @@
16
16
  目前提供了 `satori` 协议实现的有:
17
17
 
18
18
  - [Chronocat](https://chronocat.vercel.app)
19
+ - [nekobox](https://github.com/wyapx/nekobox)
19
20
  - Koishi (搭配 `@koishijs/plugin-server`)
20
21
 
21
22
  ### 使用该 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.11.4",
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.0rc2"
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 = [
@@ -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(method: str, request: StarletteRequest, func: RouteCall):
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
- res = await func(
58
- Request(
59
- cast(dict, request.headers.mutablecopy()),
60
- method,
61
- await request.json(),
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, Optional
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