reyserver 1.1.46__py3-none-any.whl → 1.1.48__py3-none-any.whl
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.
- reyserver/__init__.py +1 -0
- reyserver/rall.py +1 -0
- reyserver/rauth.py +11 -0
- reyserver/rbase.py +157 -88
- reyserver/rclient.py +89 -6
- reyserver/rfile.py +45 -27
- reyserver/rserver.py +98 -15
- {reyserver-1.1.46.dist-info → reyserver-1.1.48.dist-info}/METADATA +2 -1
- reyserver-1.1.48.dist-info/RECORD +11 -0
- reyserver-1.1.46.dist-info/RECORD +0 -10
- {reyserver-1.1.46.dist-info → reyserver-1.1.48.dist-info}/WHEEL +0 -0
- {reyserver-1.1.46.dist-info → reyserver-1.1.48.dist-info}/licenses/LICENSE +0 -0
reyserver/__init__.py
CHANGED
reyserver/rall.py
CHANGED
reyserver/rauth.py
ADDED
reyserver/rbase.py
CHANGED
@@ -9,11 +9,25 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from typing import Sequence, Literal
|
12
|
+
from typing import Sequence, Literal, NoReturn
|
13
13
|
from inspect import iscoroutinefunction
|
14
|
-
from contextlib import asynccontextmanager
|
15
|
-
from
|
16
|
-
from
|
14
|
+
from contextlib import asynccontextmanager, _AsyncGeneratorContextManager
|
15
|
+
from http import HTTPStatus
|
16
|
+
from fastapi import FastAPI, HTTPException, UploadFile as File
|
17
|
+
from fastapi.params import (
|
18
|
+
Depends,
|
19
|
+
Path,
|
20
|
+
Query,
|
21
|
+
Header,
|
22
|
+
Cookie,
|
23
|
+
Body,
|
24
|
+
Form,
|
25
|
+
File as Forms
|
26
|
+
)
|
27
|
+
from reydb.rconn import DatabaseConnectionAsync
|
28
|
+
from reydb.rorm import DatabaseORMModel, DatabaseORMSessionAsync
|
29
|
+
from reykit.rwrap import wrap_cache
|
30
|
+
from reykit.rbase import CoroutineFunctionSimple, Base, Exit, StaticMeta, ConfigMeta, throw
|
17
31
|
|
18
32
|
from . import rserver
|
19
33
|
|
@@ -22,10 +36,9 @@ __all__ = (
|
|
22
36
|
'ServerBase',
|
23
37
|
'ServerConfig',
|
24
38
|
'ServerExit',
|
25
|
-
'
|
26
|
-
'
|
27
|
-
'
|
28
|
-
'create_depend_sess'
|
39
|
+
'ServerExitAPI',
|
40
|
+
'exit_api',
|
41
|
+
'ServerBind'
|
29
42
|
)
|
30
43
|
|
31
44
|
|
@@ -50,114 +63,170 @@ class ServerExit(ServerBase, Exit):
|
|
50
63
|
"""
|
51
64
|
|
52
65
|
|
53
|
-
class
|
66
|
+
class ServerExitAPI(ServerExit, HTTPException):
|
54
67
|
"""
|
55
|
-
Server
|
68
|
+
Server exit API type.
|
56
69
|
"""
|
57
70
|
|
58
|
-
status_code: int
|
59
71
|
|
72
|
+
def exit_api(code: int = 400, text: str | None = None) -> NoReturn:
|
73
|
+
"""
|
74
|
+
Throw exception to exit API.
|
60
75
|
|
61
|
-
|
62
|
-
|
63
|
-
|
76
|
+
Parameters
|
77
|
+
----------
|
78
|
+
code : Response status code.
|
79
|
+
text : Explain text.
|
80
|
+
`None`: Use Default text.
|
81
|
+
"""
|
64
82
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
83
|
+
# Parameter.
|
84
|
+
if not 400 <= code <= 499:
|
85
|
+
throw(ValueError, code)
|
86
|
+
if text is None:
|
87
|
+
status = HTTPStatus(code)
|
88
|
+
text = status.description
|
69
89
|
|
70
|
-
|
71
|
-
|
90
|
+
# Throw exception.
|
91
|
+
raise ServerExitAPI(code, text)
|
72
92
|
|
73
93
|
|
74
|
-
class
|
94
|
+
class ServerBind(ServerBase, metaclass=StaticMeta):
|
75
95
|
"""
|
76
|
-
Server
|
96
|
+
Server API bind parameter type.
|
77
97
|
"""
|
78
98
|
|
79
|
-
status_code = status.HTTP_404_NOT_FOUND
|
80
|
-
|
81
|
-
|
82
|
-
def create_lifespan(
|
83
|
-
before: CoroutineFunctionSimple | Sequence[CoroutineFunctionSimple] | None = None,
|
84
|
-
after: CoroutineFunctionSimple | Sequence[CoroutineFunctionSimple] | None = None,
|
85
|
-
):
|
86
|
-
"""
|
87
|
-
Create function of lifespan manager.
|
88
99
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
"""
|
94
|
-
|
95
|
-
# Parameter.
|
96
|
-
if before is None:
|
97
|
-
before = ()
|
98
|
-
elif iscoroutinefunction(before):
|
99
|
-
before = (before,)
|
100
|
-
if after is None:
|
101
|
-
after = ()
|
102
|
-
elif iscoroutinefunction(after):
|
103
|
-
after = (after,)
|
104
|
-
|
105
|
-
|
106
|
-
@asynccontextmanager
|
107
|
-
async def lifespan(app: FastAPI):
|
100
|
+
def create_lifespan(
|
101
|
+
before: CoroutineFunctionSimple | Sequence[CoroutineFunctionSimple] | None = None,
|
102
|
+
after: CoroutineFunctionSimple | Sequence[CoroutineFunctionSimple] | None = None,
|
103
|
+
) -> _AsyncGeneratorContextManager[None, None]:
|
108
104
|
"""
|
109
|
-
|
105
|
+
Create asynchronous function of lifespan manager.
|
110
106
|
|
111
107
|
Parameters
|
112
108
|
----------
|
113
|
-
|
109
|
+
before : Execute before server start.
|
110
|
+
after : Execute after server end.
|
111
|
+
|
112
|
+
Returns
|
113
|
+
-------
|
114
|
+
Asynchronous function.
|
114
115
|
"""
|
115
116
|
|
116
|
-
#
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
# Parameter.
|
118
|
+
if before is None:
|
119
|
+
before = ()
|
120
|
+
elif iscoroutinefunction(before):
|
121
|
+
before = (before,)
|
122
|
+
if after is None:
|
123
|
+
after = ()
|
124
|
+
elif iscoroutinefunction(after):
|
125
|
+
after = (after,)
|
120
126
|
|
121
|
-
# After.
|
122
|
-
for task in after:
|
123
|
-
await after()
|
124
127
|
|
128
|
+
@asynccontextmanager
|
129
|
+
async def lifespan(app: FastAPI):
|
130
|
+
"""
|
131
|
+
Server lifespan manager.
|
125
132
|
|
126
|
-
|
133
|
+
Parameters
|
134
|
+
----------
|
135
|
+
app : Server APP.
|
136
|
+
"""
|
127
137
|
|
138
|
+
# Before.
|
139
|
+
for task in before:
|
140
|
+
await task()
|
141
|
+
yield
|
128
142
|
|
129
|
-
|
130
|
-
|
131
|
-
|
143
|
+
# After.
|
144
|
+
for task in after:
|
145
|
+
await after()
|
132
146
|
|
133
|
-
Parameters
|
134
|
-
----------
|
135
|
-
database : Database name.
|
136
|
-
mode : Mode.
|
137
|
-
- `Literl['sess']`: Create ORM session instance.
|
138
|
-
- `Literl['conn']`: Create connection instance.
|
139
|
-
|
140
|
-
Returns
|
141
|
-
-------
|
142
|
-
Dependencie function.
|
143
|
-
"""
|
144
147
|
|
148
|
+
return lifespan
|
145
149
|
|
146
|
-
async def depend():
|
147
|
-
"""
|
148
|
-
Dependencie function of asynchronous database.
|
149
|
-
"""
|
150
150
|
|
151
|
-
|
152
|
-
|
151
|
+
@wrap_cache
|
152
|
+
def create_depend_db(database: str, mode: Literal['sess', 'conn']) -> Depends:
|
153
|
+
"""
|
154
|
+
Create dependencie type of asynchronous database.
|
153
155
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
156
|
+
Parameters
|
157
|
+
----------
|
158
|
+
database : Database name.
|
159
|
+
mode : Mode.
|
160
|
+
- `Literl['sess']`: Create ORM session instance.
|
161
|
+
- `Literl['conn']`: Create connection instance.
|
162
|
+
|
163
|
+
Returns
|
164
|
+
-------
|
165
|
+
Dependencie type.
|
166
|
+
"""
|
161
167
|
|
162
168
|
|
163
|
-
|
169
|
+
async def depend_db():
|
170
|
+
"""
|
171
|
+
Dependencie function of asynchronous database.
|
172
|
+
"""
|
173
|
+
|
174
|
+
# Parameter.
|
175
|
+
engine = ServerConfig.server.db[database]
|
176
|
+
|
177
|
+
# Context.
|
178
|
+
if mode == 'sess':
|
179
|
+
async with engine.orm.session() as sess:
|
180
|
+
yield sess
|
181
|
+
elif mode == 'conn':
|
182
|
+
async with engine.connect() as conn:
|
183
|
+
yield conn
|
184
|
+
|
185
|
+
|
186
|
+
# Create.
|
187
|
+
depend = Depends(depend_db)
|
188
|
+
|
189
|
+
return depend
|
190
|
+
|
191
|
+
|
192
|
+
Depend = Depends
|
193
|
+
Path = Path
|
194
|
+
Query = Query
|
195
|
+
Header = Header
|
196
|
+
Cookie = Cookie
|
197
|
+
Body = Body
|
198
|
+
Form = Form
|
199
|
+
Forms = Forms
|
200
|
+
File = File
|
201
|
+
JSON = DatabaseORMModel
|
202
|
+
Conn = DatabaseConnectionAsync
|
203
|
+
Sess = DatabaseORMSessionAsync
|
204
|
+
path = Path()
|
205
|
+
'Path instance.'
|
206
|
+
query = Query()
|
207
|
+
'Query instance.'
|
208
|
+
header = Header()
|
209
|
+
'Header instance.'
|
210
|
+
cookie = Cookie()
|
211
|
+
'Cookie instance.'
|
212
|
+
body = Body()
|
213
|
+
'Body instance.'
|
214
|
+
form = Form()
|
215
|
+
'Form instance.'
|
216
|
+
forms = Forms()
|
217
|
+
'Forms instance.'
|
218
|
+
query_n = Query(None)
|
219
|
+
'Query instance, default `None`.'
|
220
|
+
header_n = Header(None)
|
221
|
+
'Header instance, default `None`.'
|
222
|
+
cookie_n = Cookie(None)
|
223
|
+
'Cookie instance, default `None`.'
|
224
|
+
body_n = Body(None)
|
225
|
+
'Body instance, default `None`.'
|
226
|
+
form_n = Form(None)
|
227
|
+
'Form instance, default `None`.'
|
228
|
+
forms_n = Forms(None)
|
229
|
+
'Forms instance, default `None`.'
|
230
|
+
|
231
|
+
|
232
|
+
Bind = ServerBind
|
reyserver/rclient.py
CHANGED
@@ -9,8 +9,10 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from
|
13
|
-
from
|
12
|
+
from typing import TypedDict
|
13
|
+
from datetime import datetime as Datetime
|
14
|
+
from reykit.ros import File, Folder, overload
|
15
|
+
from reykit.rnet import join_url, request, get_response_file_name
|
14
16
|
|
15
17
|
from .rbase import ServerBase
|
16
18
|
|
@@ -20,6 +22,9 @@ __all__ = (
|
|
20
22
|
)
|
21
23
|
|
22
24
|
|
25
|
+
FileInfo = TypedDict('FileInfo', {'create_time': Datetime, 'md5': str, 'name': str | None, 'size': int, 'note': str | None})
|
26
|
+
|
27
|
+
|
23
28
|
class ServerClient(ServerBase):
|
24
29
|
"""
|
25
30
|
Server client type.
|
@@ -64,7 +69,7 @@ class ServerClient(ServerBase):
|
|
64
69
|
"""
|
65
70
|
|
66
71
|
# Handle parameter.
|
67
|
-
url = join_url(self.url, '
|
72
|
+
url = join_url(self.url, 'files')
|
68
73
|
match source:
|
69
74
|
|
70
75
|
## File path.
|
@@ -84,7 +89,7 @@ class ServerClient(ServerBase):
|
|
84
89
|
if name is not None:
|
85
90
|
file_name = name
|
86
91
|
|
87
|
-
#
|
92
|
+
# Request.
|
88
93
|
data = {'name': file_name, 'note': note}
|
89
94
|
files = {'file': file_bytes}
|
90
95
|
response = request(url, data=data, files=files, check=True)
|
@@ -96,7 +101,85 @@ class ServerClient(ServerBase):
|
|
96
101
|
return file_id
|
97
102
|
|
98
103
|
|
99
|
-
|
104
|
+
@overload
|
105
|
+
def download_file(
|
106
|
+
self,
|
107
|
+
file_id: int,
|
108
|
+
path: None = None
|
109
|
+
) -> bytes: ...
|
110
|
+
|
111
|
+
@overload
|
112
|
+
def download_file(
|
113
|
+
self,
|
114
|
+
file_id: int,
|
115
|
+
path: str
|
116
|
+
) -> str: ...
|
117
|
+
|
118
|
+
def download_file(
|
119
|
+
self,
|
120
|
+
file_id: int,
|
121
|
+
path: str | None = None
|
122
|
+
) -> bytes | str:
|
123
|
+
"""
|
124
|
+
Download file.
|
125
|
+
|
126
|
+
Parameters
|
127
|
+
----------
|
128
|
+
file_id : File ID.
|
129
|
+
path : File save path.
|
130
|
+
- `None`: Not save and return file bytes.
|
131
|
+
- `str`: Save and return file path.
|
132
|
+
`File path`: Use this file path.
|
133
|
+
`Folder path`: Use this folder path and original name.
|
134
|
+
|
135
|
+
Returns
|
136
|
+
-------
|
137
|
+
File bytes or file path.
|
138
|
+
"""
|
139
|
+
|
140
|
+
# Parameter.
|
141
|
+
url = join_url(self.url, 'files', file_id, 'download')
|
142
|
+
|
143
|
+
# Request.
|
144
|
+
response = request(url, check=True)
|
145
|
+
file_bytes = response.content
|
146
|
+
|
147
|
+
# Not save.
|
148
|
+
if path is None:
|
149
|
+
return file_bytes
|
150
|
+
|
151
|
+
# Save.
|
152
|
+
else:
|
153
|
+
folder = Folder(path)
|
154
|
+
if folder:
|
155
|
+
file_name = get_response_file_name(response)
|
156
|
+
path = folder + file_name
|
157
|
+
file = File(path)
|
158
|
+
file(file_bytes)
|
159
|
+
return file.path
|
160
|
+
|
161
|
+
|
162
|
+
def get_file_info(
|
163
|
+
self,
|
164
|
+
file_id: int
|
165
|
+
) -> FileInfo:
|
166
|
+
"""
|
167
|
+
Query file information.
|
168
|
+
|
169
|
+
Parameters
|
170
|
+
----------
|
171
|
+
file_id : File ID.
|
172
|
+
|
173
|
+
Returns
|
174
|
+
-------
|
175
|
+
File information.
|
176
|
+
"""
|
177
|
+
|
178
|
+
# Parameter.
|
179
|
+
url = join_url(self.url, 'files', file_id)
|
100
180
|
|
181
|
+
# Request.
|
182
|
+
response = request(url, check=True)
|
183
|
+
response_dict = response.json()
|
101
184
|
|
102
|
-
|
185
|
+
return response_dict
|
reyserver/rfile.py
CHANGED
@@ -9,21 +9,12 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from fastapi import
|
13
|
-
APIRouter,
|
14
|
-
Depends,
|
15
|
-
Path,
|
16
|
-
Form,
|
17
|
-
File,
|
18
|
-
UploadFile
|
19
|
-
)
|
12
|
+
from fastapi import APIRouter
|
20
13
|
from fastapi.responses import FileResponse
|
21
14
|
from reydb import rorm
|
22
|
-
from reydb.rorm import DatabaseORMSessionAsync
|
23
|
-
from reydb.rconn import DatabaseConnectionAsync
|
24
15
|
from reykit.ros import FileStore, get_md5
|
25
16
|
|
26
|
-
from .rbase import ServerConfig,
|
17
|
+
from .rbase import ServerConfig, Bind, exit_api
|
27
18
|
|
28
19
|
|
29
20
|
__all__ = (
|
@@ -184,24 +175,29 @@ def build_file_db() -> None:
|
|
184
175
|
|
185
176
|
|
186
177
|
file_router = APIRouter()
|
187
|
-
depend_file_sess = create_depend_db('file', 'sess')
|
188
|
-
depend_file_conn = create_depend_db('file', 'conn')
|
178
|
+
depend_file_sess = Bind.create_depend_db('file', 'sess')
|
179
|
+
depend_file_conn = Bind.create_depend_db('file', 'conn')
|
189
180
|
|
190
181
|
|
191
182
|
@file_router.post('/')
|
192
183
|
async def upload_file(
|
193
|
-
file:
|
194
|
-
name: str =
|
195
|
-
note: str =
|
196
|
-
sess:
|
197
|
-
) ->
|
184
|
+
file: Bind.File = Bind.forms,
|
185
|
+
name: str = Bind.forms_n,
|
186
|
+
note: str = Bind.forms_n,
|
187
|
+
sess: Bind.Sess = depend_file_sess
|
188
|
+
) -> DatabaseORMTableInfo:
|
198
189
|
"""
|
199
190
|
Upload file.
|
200
191
|
|
201
192
|
Parameters
|
202
193
|
----------
|
203
194
|
file : File instance.
|
195
|
+
name : File name.
|
204
196
|
note : File note.
|
197
|
+
|
198
|
+
Returns
|
199
|
+
-------
|
200
|
+
File information.
|
205
201
|
"""
|
206
202
|
|
207
203
|
# Handle parameter.
|
@@ -233,15 +229,14 @@ async def upload_file(
|
|
233
229
|
|
234
230
|
# Get ID.
|
235
231
|
await sess.flush()
|
236
|
-
file_id = table_info.file_id
|
237
232
|
|
238
|
-
return
|
233
|
+
return table_info
|
239
234
|
|
240
235
|
|
241
236
|
@file_router.get('/{file_id}/download')
|
242
237
|
async def download_file(
|
243
|
-
file_id: int =
|
244
|
-
conn:
|
238
|
+
file_id: int = Bind.path,
|
239
|
+
conn: Bind.Conn = depend_file_conn
|
245
240
|
) -> FileResponse:
|
246
241
|
"""
|
247
242
|
Download file.
|
@@ -249,6 +244,10 @@ async def download_file(
|
|
249
244
|
Parameters
|
250
245
|
----------
|
251
246
|
file_id : File ID.
|
247
|
+
|
248
|
+
Returns
|
249
|
+
-------
|
250
|
+
File data.
|
252
251
|
"""
|
253
252
|
|
254
253
|
# Search.
|
@@ -267,8 +266,7 @@ async def download_file(
|
|
267
266
|
|
268
267
|
# Check.
|
269
268
|
if result.empty:
|
270
|
-
|
271
|
-
raise ServerExitHTTP404(text)
|
269
|
+
exit_api(404)
|
272
270
|
file_name, file_path = result.first()
|
273
271
|
|
274
272
|
# Response.
|
@@ -279,6 +277,26 @@ async def download_file(
|
|
279
277
|
|
280
278
|
@file_router.get('/{file_id}')
|
281
279
|
async def get_file_info(
|
282
|
-
file_id: int =
|
283
|
-
sess:
|
284
|
-
) ->
|
280
|
+
file_id: int = Bind.path,
|
281
|
+
sess: Bind.Sess = depend_file_sess
|
282
|
+
) -> DatabaseORMTableInfo:
|
283
|
+
"""
|
284
|
+
Get file information.
|
285
|
+
|
286
|
+
Parameters
|
287
|
+
----------
|
288
|
+
file_id : File ID.
|
289
|
+
|
290
|
+
Returns
|
291
|
+
-------
|
292
|
+
File information.
|
293
|
+
"""
|
294
|
+
|
295
|
+
# Get.
|
296
|
+
table_info = await sess.get(DatabaseORMTableInfo, file_id)
|
297
|
+
|
298
|
+
# Check.
|
299
|
+
if table_info is None:
|
300
|
+
exit_api(404)
|
301
|
+
|
302
|
+
return table_info
|
reyserver/rserver.py
CHANGED
@@ -9,15 +9,19 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from
|
12
|
+
from typing import Literal
|
13
|
+
from collections.abc import Sequence, Callable, Coroutine
|
13
14
|
from inspect import iscoroutinefunction
|
14
15
|
from uvicorn import run as uvicorn_run
|
15
|
-
from
|
16
|
+
from starlette.middleware.base import _StreamingResponse
|
17
|
+
from fastapi import FastAPI, Request
|
16
18
|
from fastapi.staticfiles import StaticFiles
|
19
|
+
from fastapi.middleware.gzip import GZipMiddleware
|
20
|
+
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
|
17
21
|
from reydb import DatabaseAsync
|
18
|
-
from reykit.rbase import CoroutineFunctionSimple, Singleton, throw
|
22
|
+
from reykit.rbase import CallableT, CoroutineFunctionSimple, Singleton, throw
|
19
23
|
|
20
|
-
from .rbase import ServerBase, ServerConfig,
|
24
|
+
from .rbase import ServerBase, ServerConfig, Bind
|
21
25
|
|
22
26
|
|
23
27
|
__all__ = (
|
@@ -42,31 +46,33 @@ class Server(ServerBase, Singleton):
|
|
42
46
|
after: CoroutineFunctionSimple | Sequence[CoroutineFunctionSimple] | None = None,
|
43
47
|
ssl_cert: str | None = None,
|
44
48
|
ssl_key: str | None = None,
|
49
|
+
debug: bool = False
|
45
50
|
) -> None:
|
46
51
|
"""
|
47
52
|
Build instance attributes.
|
48
53
|
|
49
54
|
Parameters
|
50
55
|
----------
|
51
|
-
db : Asynchronous database.
|
56
|
+
db : Asynchronous database, must include database engines with APIs.
|
52
57
|
public : Public directory.
|
53
58
|
depend : Global api dependencies.
|
54
59
|
before : Execute before server start.
|
55
60
|
after : Execute after server end.
|
56
61
|
ssl_cert : SSL certificate file path.
|
57
62
|
ssl_key : SSL key file path.
|
63
|
+
debug : Whether use development mode debug server.
|
58
64
|
"""
|
59
65
|
|
60
66
|
# Parameter.
|
61
67
|
if type(ssl_cert) != type(ssl_key):
|
62
68
|
throw(AssertionError, ssl_cert, ssl_key)
|
63
|
-
lifespan = create_lifespan(before, after)
|
69
|
+
lifespan = Bind.create_lifespan(before, after)
|
64
70
|
if depend is None:
|
65
71
|
depend = ()
|
66
72
|
elif iscoroutinefunction(depend):
|
67
73
|
depend = (depend,)
|
68
74
|
depend = [
|
69
|
-
|
75
|
+
Bind.Depend(task)
|
70
76
|
for task in depend
|
71
77
|
]
|
72
78
|
|
@@ -80,18 +86,57 @@ class Server(ServerBase, Singleton):
|
|
80
86
|
self.app = FastAPI(
|
81
87
|
dependencies=depend,
|
82
88
|
lifespan=lifespan,
|
83
|
-
debug=
|
89
|
+
debug=debug
|
84
90
|
)
|
85
91
|
|
86
|
-
## Static.
|
87
92
|
if public is not None:
|
88
93
|
subapp = StaticFiles(directory=public, html=True)
|
89
94
|
self.app.mount('/', subapp)
|
95
|
+
self.wrap_middleware = self.app.middleware('http')
|
96
|
+
'Decorator, add middleware to APP.'
|
90
97
|
|
91
|
-
|
98
|
+
# Middleware
|
99
|
+
self.app.add_middleware(GZipMiddleware)
|
100
|
+
if not debug:
|
101
|
+
self.app.add_middleware(HTTPSRedirectMiddleware)
|
102
|
+
self.__add_default_middleware()
|
92
103
|
|
93
|
-
|
104
|
+
# API.
|
94
105
|
self.api_file_dir: str
|
106
|
+
'File API store directory path.'
|
107
|
+
|
108
|
+
|
109
|
+
def __add_default_middleware(self) -> None:
|
110
|
+
"""
|
111
|
+
Add default handle middleware.
|
112
|
+
"""
|
113
|
+
|
114
|
+
# Add.
|
115
|
+
@self.wrap_middleware
|
116
|
+
async def foo(
|
117
|
+
request: Request,
|
118
|
+
call_next: Callable[[Request], Coroutine[None, None, _StreamingResponse]]
|
119
|
+
) -> _StreamingResponse:
|
120
|
+
"""
|
121
|
+
Default handle middleware.
|
122
|
+
|
123
|
+
Parameters
|
124
|
+
----------
|
125
|
+
Reqeust : Request instance.
|
126
|
+
call_next : Next middleware.
|
127
|
+
"""
|
128
|
+
|
129
|
+
# Before.
|
130
|
+
...
|
131
|
+
|
132
|
+
# Next.
|
133
|
+
response = await call_next(request)
|
134
|
+
|
135
|
+
# After.
|
136
|
+
if request.method == 'POST':
|
137
|
+
response.status_code = 201
|
138
|
+
|
139
|
+
return response
|
95
140
|
|
96
141
|
|
97
142
|
def run(self) -> None:
|
@@ -107,16 +152,54 @@ class Server(ServerBase, Singleton):
|
|
107
152
|
)
|
108
153
|
|
109
154
|
|
110
|
-
def
|
155
|
+
def set_doc(
|
156
|
+
self,
|
157
|
+
version: str | None = None,
|
158
|
+
title: str | None = None,
|
159
|
+
summary: str | None = None,
|
160
|
+
desc: str | None = None,
|
161
|
+
contact: dict[Literal['name', 'email', 'url'], str] | None = None
|
162
|
+
) -> None:
|
163
|
+
"""
|
164
|
+
Set server document.
|
165
|
+
|
166
|
+
Parameters
|
167
|
+
----------
|
168
|
+
version : Server version.
|
169
|
+
title : Server title.
|
170
|
+
summary : Server summary.
|
171
|
+
desc : Server description.
|
172
|
+
contact : Server contact information.
|
173
|
+
"""
|
174
|
+
|
175
|
+
# Parameter.
|
176
|
+
set_dict = {
|
177
|
+
'version': version,
|
178
|
+
'title': title,
|
179
|
+
'summary': summary,
|
180
|
+
'description': desc,
|
181
|
+
'contact': contact
|
182
|
+
}
|
183
|
+
|
184
|
+
# Set.
|
185
|
+
for key, value in set_dict.items():
|
186
|
+
if value is not None:
|
187
|
+
setattr(self.app, key, value)
|
188
|
+
|
189
|
+
|
190
|
+
def add_api_auth(self):
|
191
|
+
"""
|
192
|
+
Add Authentication API.
|
193
|
+
Note: must include database engine of `auth` name.
|
194
|
+
"""
|
111
195
|
|
112
|
-
|
113
|
-
async def test():
|
114
|
-
return {'message': 'test'}
|
196
|
+
...
|
115
197
|
|
116
198
|
|
117
199
|
def add_api_file(self, file_dir: str = 'file') -> None:
|
118
200
|
"""
|
119
201
|
Add file API.
|
202
|
+
Note: must include database engine of `file` name.
|
120
203
|
|
121
204
|
Parameters
|
122
205
|
----------
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: reyserver
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.48
|
4
4
|
Summary: Backend server method set.
|
5
5
|
Project-URL: homepage, https://github.com/reyxbo/reyserver/
|
6
6
|
Author-email: Rey <reyxbo@163.com>
|
@@ -14,6 +14,7 @@ License: Copyright 2025 ReyXBo
|
|
14
14
|
License-File: LICENSE
|
15
15
|
Keywords: API,async,asynchronous,backend,rey,reyxbo,server
|
16
16
|
Requires-Python: >=3.12
|
17
|
+
Requires-Dist: email-validator
|
17
18
|
Requires-Dist: fastapi
|
18
19
|
Requires-Dist: python-multipart
|
19
20
|
Requires-Dist: reydb
|
@@ -0,0 +1,11 @@
|
|
1
|
+
reyserver/__init__.py,sha256=7GX64p7uI2eetJH9NJ-DTg-8iyQwOsGcviADFJCPxVA,373
|
2
|
+
reyserver/rall.py,sha256=riyDRTUsigco_Bee1H4aZFb8IgvjnxdX9qcnVb9i9mE,270
|
3
|
+
reyserver/rauth.py,sha256=QyY4gZ0ulpH9Kxvux_jnZBhzfWZZEuOWB1oYU9uzCnY,167
|
4
|
+
reyserver/rbase.py,sha256=IUVkkNsLmQh-QRLX6qtbCjPZAbQAsxoe0goPLCxG9KA,5283
|
5
|
+
reyserver/rclient.py,sha256=pTJtn78jPKgFo5EoQwZRdM0cYHdCs7QUKqfl-jUBRgk,4220
|
6
|
+
reyserver/rfile.py,sha256=6Dwq8_X1kiY1n-9RhbLL3hvdhTAnsAUHyXivcviYcoA,8888
|
7
|
+
reyserver/rserver.py,sha256=hqpemzJHO6xHy_7pO3cvvjnfy8Yfqy8HfyIq4sjk4Dc,5889
|
8
|
+
reyserver-1.1.48.dist-info/METADATA,sha256=T6Q2BrTheAiAziG15T9seCxh_Yi9IRcplL35YTa-wGo,1689
|
9
|
+
reyserver-1.1.48.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
+
reyserver-1.1.48.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
11
|
+
reyserver-1.1.48.dist-info/RECORD,,
|
@@ -1,10 +0,0 @@
|
|
1
|
-
reyserver/__init__.py,sha256=JmDkcdP7oxmehE53rRRL_zhxmPinAbJRONpQp5qhsGI,340
|
2
|
-
reyserver/rall.py,sha256=6vqacf9erEfVfK5sgGJMDXD1h4ebt5gDN7NrPdtELms,248
|
3
|
-
reyserver/rbase.py,sha256=6mfTSuVzJGTK6Ch0HNlN0bmKIkPMLUlUAAE_EGt-1uo,3298
|
4
|
-
reyserver/rclient.py,sha256=OjY_OEH_USrJK8TuCevXG6jNPVbM0lN-xMBozB7kSM8,2195
|
5
|
-
reyserver/rfile.py,sha256=pA1LdHjBDJwj7S2k7cemwsHO19Oo0bHtkX_r79RBlJA,8770
|
6
|
-
reyserver/rserver.py,sha256=lsOr_fhiAukQhLHfqH1OfZByuUEzjFoJtqLI7BoNxvI,3401
|
7
|
-
reyserver-1.1.46.dist-info/METADATA,sha256=3E8xJWPt5S6j3piVBeuAbFSXzqbTHq6hhrEp5EJ0YLg,1658
|
8
|
-
reyserver-1.1.46.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
9
|
-
reyserver-1.1.46.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
10
|
-
reyserver-1.1.46.dist-info/RECORD,,
|
File without changes
|
File without changes
|