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 CHANGED
@@ -11,5 +11,6 @@ Modules
11
11
  -------
12
12
  rall : All methods.
13
13
  rbase : Base methods.
14
+ rfile : File methods.
14
15
  rserver : Server methods.
15
16
  """
reyserver/rall.py CHANGED
@@ -10,4 +10,5 @@
10
10
 
11
11
 
12
12
  from .rbase import *
13
+ from .rfile import *
13
14
  from .rserver import *
reyserver/rbase.py CHANGED
@@ -14,6 +14,7 @@ from reykit.rbase import Base
14
14
 
15
15
  __all__ = (
16
16
  'ServerBase',
17
+ 'ServerAPI'
17
18
  )
18
19
 
19
20
 
@@ -21,3 +22,9 @@ class ServerBase(Base):
21
22
  """
22
23
  Server base type.
23
24
  """
25
+
26
+
27
+ class ServerAPI(ServerBase):
28
+ """
29
+ Server API type.
30
+ """
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 types import CoroutineType
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 fastapi.responses import HTMLResponse
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: CoroutineFunction | Sequence[CoroutineFunction] | None = None,
50
- before: CoroutineFunction | Sequence[CoroutineFunction] | None = None,
51
- after: CoroutineFunction | Sequence[CoroutineFunction] | None = None,
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reyserver
3
- Version: 1.1.36
3
+ Version: 1.1.38
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>
@@ -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,,