reyserver 1.1.36__py3-none-any.whl → 1.1.38__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/rbase.py +7 -0
- reyserver/rfile.py +271 -0
- reyserver/rserver.py +5 -16
- {reyserver-1.1.36.dist-info → reyserver-1.1.38.dist-info}/METADATA +1 -1
- reyserver-1.1.38.dist-info/RECORD +9 -0
- reyserver-1.1.36.dist-info/RECORD +0 -8
- {reyserver-1.1.36.dist-info → reyserver-1.1.38.dist-info}/WHEEL +0 -0
- {reyserver-1.1.36.dist-info → reyserver-1.1.38.dist-info}/licenses/LICENSE +0 -0
reyserver/__init__.py
CHANGED
reyserver/rall.py
CHANGED
reyserver/rbase.py
CHANGED
reyserver/rfile.py
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
# !/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
@Time : 2025-10-06 18:23:51
|
6
|
+
@Author : Rey
|
7
|
+
@Contact : reyxbo@163.com
|
8
|
+
@Explain : File methods. Can create database used `self.build_db` function.
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
from fastapi import APIRouter
|
13
|
+
from reydb import rorm
|
14
|
+
from reydb.rdb import DatabaseAsync
|
15
|
+
|
16
|
+
from . import rserver
|
17
|
+
from .rbase import ServerAPI
|
18
|
+
|
19
|
+
|
20
|
+
__all__ = (
|
21
|
+
'file_router',
|
22
|
+
'DatabaseORMTableInfo',
|
23
|
+
'DatabaseORMTableData',
|
24
|
+
'build_file_db'
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
file_router = APIRouter()
|
29
|
+
|
30
|
+
|
31
|
+
class DatabaseORMTableInfo(rorm.Model, table=True):
|
32
|
+
"""
|
33
|
+
Database `info` table ORM model.
|
34
|
+
"""
|
35
|
+
|
36
|
+
__name__ = 'info'
|
37
|
+
__comment__ = 'File information table.'
|
38
|
+
create_time: rorm.Datetime = rorm.Field(field_default=':create_time', not_null=True, index_n=True, comment='Record create time.')
|
39
|
+
field_id: int = rorm.Field(rorm.types_mysql.MEDIUMINT(unsigned=True), key_auto=True, comment='File self increase ID.')
|
40
|
+
md5: str = rorm.Field(rorm.types.CHAR(32), not_null=True, index_n=True, comment='File MD5.')
|
41
|
+
name: str = rorm.Field(rorm.types.VARCHAR(260), index_n=True, comment='File name.')
|
42
|
+
note: str = rorm.Field(rorm.types.VARCHAR(500), comment='File note.')
|
43
|
+
|
44
|
+
|
45
|
+
class DatabaseORMTableData(rorm.Model, table=True):
|
46
|
+
"""
|
47
|
+
Database `data` table ORM model.
|
48
|
+
"""
|
49
|
+
|
50
|
+
__name__ = 'data'
|
51
|
+
__comment__ = 'File data table.'
|
52
|
+
md5: str = rorm.Field(rorm.types.CHAR(32), key=True, comment='File MD5.')
|
53
|
+
size: int = rorm.Field(rorm.types_mysql.INTEGER(unsigned=True), not_null=True, comment='File bytes size.')
|
54
|
+
path: str = rorm.Field(rorm.types.VARCHAR(4095), not_null=True, comment='File disk storage path.')
|
55
|
+
|
56
|
+
|
57
|
+
def build_file_db(db: DatabaseAsync) -> None:
|
58
|
+
"""
|
59
|
+
Check and build all standard databases and tables, by `self.db_names`.
|
60
|
+
|
61
|
+
Parameters
|
62
|
+
db : Asynchronous database instance.
|
63
|
+
"""
|
64
|
+
|
65
|
+
# Set parameter.
|
66
|
+
database = db.database
|
67
|
+
|
68
|
+
## Table.
|
69
|
+
tables = [DatabaseORMTableInfo, DatabaseORMTableData]
|
70
|
+
|
71
|
+
## View.
|
72
|
+
views = [
|
73
|
+
{
|
74
|
+
'path': 'data_info',
|
75
|
+
'select': (
|
76
|
+
'SELECT `b`.`last_time`, `a`.`md5`, `a`.`size`, `b`.`names`, `b`.`notes`\n'
|
77
|
+
f'FROM `{database}`.`data` AS `a`\n'
|
78
|
+
'LEFT JOIN (\n'
|
79
|
+
' SELECT\n'
|
80
|
+
' `md5`,\n'
|
81
|
+
" GROUP_CONCAT(DISTINCT(`name`) ORDER BY `create_time` DESC SEPARATOR ' | ') AS `names`,\n"
|
82
|
+
" GROUP_CONCAT(DISTINCT(`note`) ORDER BY `create_time` DESC SEPARATOR ' | ') AS `notes`,\n"
|
83
|
+
' MAX(`create_time`) as `last_time`\n'
|
84
|
+
f' FROM `{database}`.`info`\n'
|
85
|
+
' GROUP BY `md5`\n'
|
86
|
+
' ORDER BY `last_time` DESC\n'
|
87
|
+
') AS `b`\n'
|
88
|
+
'ON `a`.`md5` = `b`.`md5`\n'
|
89
|
+
'ORDER BY `last_time` DESC'
|
90
|
+
)
|
91
|
+
}
|
92
|
+
]
|
93
|
+
|
94
|
+
## View stats.
|
95
|
+
views_stats = [
|
96
|
+
{
|
97
|
+
'path': 'stats',
|
98
|
+
'items': [
|
99
|
+
{
|
100
|
+
'name': 'count',
|
101
|
+
'select': (
|
102
|
+
'SELECT COUNT(1)\n'
|
103
|
+
f'FROM `{database}`.`info`'
|
104
|
+
),
|
105
|
+
'comment': 'File information count.'
|
106
|
+
},
|
107
|
+
{
|
108
|
+
'name': 'past_day_count',
|
109
|
+
'select': (
|
110
|
+
'SELECT COUNT(1)\n'
|
111
|
+
f'FROM `{database}`.`info`\n'
|
112
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) = 0'
|
113
|
+
),
|
114
|
+
'comment': 'File information count in the past day.'
|
115
|
+
},
|
116
|
+
{
|
117
|
+
'name': 'past_week_count',
|
118
|
+
'select': (
|
119
|
+
'SELECT COUNT(1)\n'
|
120
|
+
f'FROM `{database}`.`info`\n'
|
121
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 6'
|
122
|
+
),
|
123
|
+
'comment': 'File information count in the past week.'
|
124
|
+
},
|
125
|
+
{
|
126
|
+
'name': 'past_month_count',
|
127
|
+
'select': (
|
128
|
+
'SELECT COUNT(1)\n'
|
129
|
+
f'FROM `{database}`.`info`\n'
|
130
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 29'
|
131
|
+
),
|
132
|
+
'comment': 'File information count in the past month.'
|
133
|
+
},
|
134
|
+
{
|
135
|
+
'name': 'data_count',
|
136
|
+
'select': (
|
137
|
+
'SELECT COUNT(1)\n'
|
138
|
+
f'FROM `{database}`.`data`'
|
139
|
+
),
|
140
|
+
'comment': 'File data unique count.'
|
141
|
+
},
|
142
|
+
{
|
143
|
+
'name': 'total_size',
|
144
|
+
'select': (
|
145
|
+
'SELECT FORMAT(SUM(`size`), 0)\n'
|
146
|
+
f'FROM `{database}`.`data`'
|
147
|
+
),
|
148
|
+
'comment': 'File total byte size.'
|
149
|
+
},
|
150
|
+
{
|
151
|
+
'name': 'avg_size',
|
152
|
+
'select': (
|
153
|
+
'SELECT FORMAT(AVG(`size`), 0)\n'
|
154
|
+
f'FROM `{database}`.`data`'
|
155
|
+
),
|
156
|
+
'comment': 'File average byte size.'
|
157
|
+
},
|
158
|
+
{
|
159
|
+
'name': 'max_size',
|
160
|
+
'select': (
|
161
|
+
'SELECT FORMAT(MAX(`size`), 0)\n'
|
162
|
+
f'FROM `{database}`.`data`'
|
163
|
+
),
|
164
|
+
'comment': 'File maximum byte size.'
|
165
|
+
},
|
166
|
+
{
|
167
|
+
'name': 'last_time',
|
168
|
+
'select': (
|
169
|
+
'SELECT MAX(`create_time`)\n'
|
170
|
+
f'FROM `{database}`.`info`'
|
171
|
+
),
|
172
|
+
'comment': 'File last record create time.'
|
173
|
+
}
|
174
|
+
]
|
175
|
+
}
|
176
|
+
]
|
177
|
+
|
178
|
+
# Build.
|
179
|
+
db.build.build(tables=tables, views=views, views_stats=views_stats)
|
180
|
+
|
181
|
+
|
182
|
+
@file_router.post('/upload')
|
183
|
+
def upload(
|
184
|
+
source: bytes,
|
185
|
+
name: str | None = None,
|
186
|
+
note: str | None = None
|
187
|
+
) -> int:
|
188
|
+
"""
|
189
|
+
Upload file.
|
190
|
+
|
191
|
+
Parameters
|
192
|
+
----------
|
193
|
+
source : File path or file bytes.
|
194
|
+
name : File name.
|
195
|
+
- `None`: Automatic set.
|
196
|
+
`parameter 'file' is 'str'`: Use path file name.
|
197
|
+
`parameter 'file' is 'bytes'`: No name.
|
198
|
+
- `str`: Use this name.
|
199
|
+
note : File note.
|
200
|
+
|
201
|
+
Returns
|
202
|
+
-------
|
203
|
+
File ID.
|
204
|
+
"""
|
205
|
+
|
206
|
+
# Handle parameter.
|
207
|
+
conn = self.db.connect()
|
208
|
+
match source:
|
209
|
+
|
210
|
+
## File path.
|
211
|
+
case str():
|
212
|
+
file = File(source)
|
213
|
+
file_bytes = file.bytes
|
214
|
+
file_md5 = get_md5(file_bytes)
|
215
|
+
file_name = file.name_suffix
|
216
|
+
|
217
|
+
## File bytes.
|
218
|
+
case bytes() | bytearray():
|
219
|
+
if type(source) == bytearray:
|
220
|
+
source = bytes(source)
|
221
|
+
file_bytes = source
|
222
|
+
file_md5 = get_md5(file_bytes)
|
223
|
+
file_name = None
|
224
|
+
|
225
|
+
## File name.
|
226
|
+
if name is not None:
|
227
|
+
file_name = name
|
228
|
+
|
229
|
+
## File size.
|
230
|
+
file_size = len(file_bytes)
|
231
|
+
|
232
|
+
# Exist.
|
233
|
+
exist = conn.execute.exist(
|
234
|
+
(self.db_names['file'], self.db_names['file.data']),
|
235
|
+
'`md5` = :file_md5',
|
236
|
+
file_md5=file_md5
|
237
|
+
)
|
238
|
+
|
239
|
+
# Upload.
|
240
|
+
|
241
|
+
## Data.
|
242
|
+
if not exist:
|
243
|
+
data = {
|
244
|
+
'md5': file_md5,
|
245
|
+
'size': file_size,
|
246
|
+
'bytes': file_bytes
|
247
|
+
}
|
248
|
+
conn.execute.insert(
|
249
|
+
(self.db_names['file'], self.db_names['file.data']),
|
250
|
+
data,
|
251
|
+
'ignore'
|
252
|
+
)
|
253
|
+
|
254
|
+
## Information.
|
255
|
+
data = {
|
256
|
+
'md5': file_md5,
|
257
|
+
'name': file_name,
|
258
|
+
'note': note
|
259
|
+
}
|
260
|
+
conn.execute.insert(
|
261
|
+
(self.db_names['file'], self.db_names['file.information']),
|
262
|
+
data
|
263
|
+
)
|
264
|
+
|
265
|
+
# Get ID.
|
266
|
+
file_id = conn.insert_id
|
267
|
+
|
268
|
+
# Commit.
|
269
|
+
conn.commit()
|
270
|
+
|
271
|
+
return file_id
|
reyserver/rserver.py
CHANGED
@@ -11,19 +11,11 @@
|
|
11
11
|
|
12
12
|
from typing import Literal
|
13
13
|
from collections.abc import Sequence, Callable, Coroutine
|
14
|
-
from
|
15
|
-
from inspect import iscoroutinefunction, iscoroutine
|
16
|
-
from fastapi import FastAPI, Depends as get_depends
|
17
|
-
from fastapi.params import Depends
|
18
|
-
# from fastapi.middleware.cors import CORSMiddleware
|
14
|
+
from fastapi import FastAPI
|
19
15
|
from fastapi.middleware.gzip import GZipMiddleware
|
20
|
-
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
21
|
-
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
|
22
16
|
from fastapi.staticfiles import StaticFiles
|
23
17
|
from uvicorn import run as uvicorn_run
|
24
|
-
from
|
25
|
-
from reykit.ros import File, Folder
|
26
|
-
from reykit.rbase import CoroutineFunction
|
18
|
+
from reykit.rbase import CoroutineFunctionSimple
|
27
19
|
|
28
20
|
from .rbase import ServerBase
|
29
21
|
|
@@ -33,9 +25,6 @@ __all__ = (
|
|
33
25
|
)
|
34
26
|
|
35
27
|
|
36
|
-
type CoroutineFunction = Callable[[], Coroutine]
|
37
|
-
|
38
|
-
|
39
28
|
class Server(ServerBase):
|
40
29
|
"""
|
41
30
|
Server type.
|
@@ -46,9 +35,9 @@ class Server(ServerBase):
|
|
46
35
|
def __init__(
|
47
36
|
self,
|
48
37
|
public: str | None = None,
|
49
|
-
depend:
|
50
|
-
before:
|
51
|
-
after:
|
38
|
+
depend: CoroutineFunctionSimple | Sequence[CoroutineFunctionSimple] | None = None,
|
39
|
+
before: CoroutineFunctionSimple | Sequence[CoroutineFunctionSimple] | None = None,
|
40
|
+
after: CoroutineFunctionSimple | Sequence[CoroutineFunctionSimple] | None = None,
|
52
41
|
ssl_cert: str | None = None,
|
53
42
|
ssl_key: str | None = None,
|
54
43
|
) -> None:
|
@@ -0,0 +1,9 @@
|
|
1
|
+
reyserver/__init__.py,sha256=ZNzM6wBvBSXe1LgV40ZJ1WIAbejWNYGl8x22dmt8C60,289
|
2
|
+
reyserver/rall.py,sha256=F-vUJIf5DgP0FXI0pdTrEeEiMtN-g81_yTo4ibUL9xk,233
|
3
|
+
reyserver/rbase.py,sha256=TtCmqjofwKkE0vdOIc5WhWxbgAUd8pFgx26-VON11yA,397
|
4
|
+
reyserver/rfile.py,sha256=P3i1wa2JYsgNFrm0pDCsDN_zFo_Xpv4XigePotVzn8s,8213
|
5
|
+
reyserver/rserver.py,sha256=NyI9_evkZ2uGXajI75X8Paj18N1S2f9xUGgLGeQ_2ag,2546
|
6
|
+
reyserver-1.1.38.dist-info/METADATA,sha256=CuZu-kkGUgw0qSvNpzMYVlhIhvF2QL7uG36GZuEn9qE,1549
|
7
|
+
reyserver-1.1.38.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
8
|
+
reyserver-1.1.38.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
9
|
+
reyserver-1.1.38.dist-info/RECORD,,
|
@@ -1,8 +0,0 @@
|
|
1
|
-
reyserver/__init__.py,sha256=xNiwJwOqcsCbTODxZict7-MsU0cWlzYuIEE770o9-VI,266
|
2
|
-
reyserver/rall.py,sha256=4z6iHnQ43Y1UYOLoNdPN117h5LKNUWm6fhOZ5-QJK8w,211
|
3
|
-
reyserver/rbase.py,sha256=TANYMgAdpgCZoMv3WK72rARo0zNQeCFcraWYXZu96WI,306
|
4
|
-
reyserver/rserver.py,sha256=AYAB5wXObhuFrC3prz_MYyXOKadCX2hMR-llxHSF6mI,2976
|
5
|
-
reyserver-1.1.36.dist-info/METADATA,sha256=4AvsxMuZ11NmQuM4C3DH69sqyhvhSsp4ApIzr-GXS0Y,1549
|
6
|
-
reyserver-1.1.36.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
7
|
-
reyserver-1.1.36.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
8
|
-
reyserver-1.1.36.dist-info/RECORD,,
|
File without changes
|
File without changes
|