reyserver 1.1.48__py3-none-any.whl → 1.1.50__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/rauth.py +240 -0
- reyserver/rfile.py +36 -33
- reyserver/rserver.py +28 -7
- {reyserver-1.1.48.dist-info → reyserver-1.1.50.dist-info}/METADATA +1 -1
- reyserver-1.1.50.dist-info/RECORD +11 -0
- reyserver-1.1.48.dist-info/RECORD +0 -11
- {reyserver-1.1.48.dist-info → reyserver-1.1.50.dist-info}/WHEEL +0 -0
- {reyserver-1.1.48.dist-info → reyserver-1.1.50.dist-info}/licenses/LICENSE +0 -0
reyserver/rauth.py
CHANGED
@@ -9,3 +9,243 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
+
from fastapi import APIRouter
|
13
|
+
from reydb import rorm, DatabaseEngine, DatabaseEngineAsync
|
14
|
+
from reykit.rdata import encode_jwt, decode_jwt, hash_bcrypt, is_hash_bcrypt
|
15
|
+
from reykit.rtime import now
|
16
|
+
|
17
|
+
from .rbase import ServerConfig, Bind, exit_api
|
18
|
+
|
19
|
+
|
20
|
+
__all__ = (
|
21
|
+
'DatabaseORMTableUser',
|
22
|
+
'DatabaseORMTableRole',
|
23
|
+
'DatabaseORMTablePerm',
|
24
|
+
'DatabaseORMTableUserRole',
|
25
|
+
'DatabaseORMTableRolePerm',
|
26
|
+
'build_auth_db',
|
27
|
+
'auth_router'
|
28
|
+
)
|
29
|
+
|
30
|
+
|
31
|
+
class DatabaseORMTableUser(rorm.Model, table=True):
|
32
|
+
"""
|
33
|
+
Database `user` table ORM model.
|
34
|
+
"""
|
35
|
+
|
36
|
+
__name__ = 'user'
|
37
|
+
__comment__ = 'User information table.'
|
38
|
+
create_time: rorm.Datetime = rorm.Field(field_default=':create_time', not_null=True, index_n=True, comment='Record create time.')
|
39
|
+
update_time: rorm.Datetime = rorm.Field(field_default=':update_time', not_null=True, index_n=True, comment='Record update time.')
|
40
|
+
user_id: int = rorm.Field(rorm.types_mysql.MEDIUMINT(unsigned=True), key_auto=True, comment='User ID.')
|
41
|
+
name: str = rorm.Field(rorm.types.VARCHAR(50), not_null=True, index_u=True, comment='User name.')
|
42
|
+
password: str = rorm.Field(rorm.types.CHAR(60), not_null=True, comment='User password, encrypted with "bcrypt".')
|
43
|
+
email: rorm.Email = rorm.Field(rorm.types.VARCHAR(255), index_u=True, comment='User email.')
|
44
|
+
phone: str = rorm.Field(rorm.types.CHAR(11), index_u=True, comment='User phone.')
|
45
|
+
avatar: int = rorm.Field(rorm.types_mysql.MEDIUMINT(unsigned=True), comment='User avatar file ID.')
|
46
|
+
is_valid: bool = rorm.Field(rorm.types_mysql.TINYINT(unsigned=True), field_default='1', not_null=True, comment='Is the valid.')
|
47
|
+
|
48
|
+
|
49
|
+
class DatabaseORMTableRole(rorm.Model, table=True):
|
50
|
+
"""
|
51
|
+
Database `role` table ORM model.
|
52
|
+
"""
|
53
|
+
|
54
|
+
__name__ = 'role'
|
55
|
+
__comment__ = 'Role information table.'
|
56
|
+
create_time: rorm.Datetime = rorm.Field(field_default=':create_time', not_null=True, index_n=True, comment='Record create time.')
|
57
|
+
update_time: rorm.Datetime = rorm.Field(field_default=':update_time', not_null=True, index_n=True, comment='Record update time.')
|
58
|
+
role_id: int = rorm.Field(rorm.types_mysql.SMALLINT(unsigned=True), key_auto=True, comment='Role ID.')
|
59
|
+
name: str = rorm.Field(rorm.types.VARCHAR(50), not_null=True, index_u=True, comment='Role name.')
|
60
|
+
desc: str = rorm.Field(rorm.types.VARCHAR(500), comment='Role description.')
|
61
|
+
|
62
|
+
|
63
|
+
class DatabaseORMTablePerm(rorm.Model, table=True):
|
64
|
+
"""
|
65
|
+
Database `perm` table ORM model.
|
66
|
+
"""
|
67
|
+
|
68
|
+
__name__ = 'perm'
|
69
|
+
__comment__ = 'API permission information table.'
|
70
|
+
create_time: rorm.Datetime = rorm.Field(field_default=':create_time', not_null=True, index_n=True, comment='Record create time.')
|
71
|
+
update_time: rorm.Datetime = rorm.Field(field_default=':update_time', not_null=True, index_n=True, comment='Record update time.')
|
72
|
+
perm_id: int = rorm.Field(rorm.types_mysql.SMALLINT(unsigned=True), key_auto=True, comment='Permission ID.')
|
73
|
+
name: str = rorm.Field(rorm.types.VARCHAR(50), not_null=True, index_u=True, comment='Permission name.')
|
74
|
+
desc: str = rorm.Field(rorm.types.VARCHAR(500), comment='Permission description.')
|
75
|
+
method: str = rorm.Field(rorm.types.VARCHAR(7), comment='API request method regular expression "match" pattern.')
|
76
|
+
path: str = rorm.Field(rorm.types.VARCHAR(1000), comment='API resource path regular expression "match" pattern.')
|
77
|
+
|
78
|
+
|
79
|
+
class DatabaseORMTableUserRole(rorm.Model, table=True):
|
80
|
+
"""
|
81
|
+
Database `user_role` table ORM model.
|
82
|
+
"""
|
83
|
+
|
84
|
+
__name__ = 'user_role'
|
85
|
+
__comment__ = 'User and role association table.'
|
86
|
+
create_time: rorm.Datetime = rorm.Field(field_default=':create_time', not_null=True, index_n=True, comment='Record create time.')
|
87
|
+
update_time: rorm.Datetime = rorm.Field(field_default=':update_time', not_null=True, index_n=True, comment='Record update time.')
|
88
|
+
user_id: int = rorm.Field(rorm.types_mysql.MEDIUMINT(unsigned=True), key=True, comment='User ID.')
|
89
|
+
role_id: int = rorm.Field(rorm.types_mysql.SMALLINT(unsigned=True), key=True, comment='Role ID.')
|
90
|
+
|
91
|
+
|
92
|
+
class DatabaseORMTableRolePerm(rorm.Model, table=True):
|
93
|
+
"""
|
94
|
+
Database `role_perm` table ORM model.
|
95
|
+
"""
|
96
|
+
|
97
|
+
__name__ = 'role_perm'
|
98
|
+
__comment__ = 'role and permission association table.'
|
99
|
+
create_time: rorm.Datetime = rorm.Field(field_default=':create_time', not_null=True, index_n=True, comment='Record create time.')
|
100
|
+
update_time: rorm.Datetime = rorm.Field(field_default=':update_time', not_null=True, index_n=True, comment='Record update time.')
|
101
|
+
role_id: int = rorm.Field(rorm.types_mysql.SMALLINT(unsigned=True), key=True, comment='Role ID.')
|
102
|
+
perm_id: int = rorm.Field(rorm.types_mysql.SMALLINT(unsigned=True), key=True, comment='Permission ID.')
|
103
|
+
|
104
|
+
|
105
|
+
def build_auth_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
|
106
|
+
"""
|
107
|
+
Check and build `auth` database tables.
|
108
|
+
|
109
|
+
Parameters
|
110
|
+
----------
|
111
|
+
db : Database engine instance.
|
112
|
+
"""
|
113
|
+
|
114
|
+
# Set parameter.
|
115
|
+
database = engine.database
|
116
|
+
|
117
|
+
## Table.
|
118
|
+
tables = [
|
119
|
+
DatabaseORMTableUser,
|
120
|
+
DatabaseORMTableRole,
|
121
|
+
DatabaseORMTablePerm,
|
122
|
+
DatabaseORMTableUserRole,
|
123
|
+
DatabaseORMTableRolePerm
|
124
|
+
]
|
125
|
+
|
126
|
+
## View stats.
|
127
|
+
views_stats = [
|
128
|
+
{
|
129
|
+
'path': 'stats',
|
130
|
+
'items': [
|
131
|
+
{
|
132
|
+
'name': 'user_count',
|
133
|
+
'select': (
|
134
|
+
'SELECT COUNT(1)\n'
|
135
|
+
f'FROM `{database}`.`user`'
|
136
|
+
),
|
137
|
+
'comment': 'User information count.'
|
138
|
+
},
|
139
|
+
{
|
140
|
+
'name': 'role_count',
|
141
|
+
'select': (
|
142
|
+
'SELECT COUNT(1)\n'
|
143
|
+
f'FROM `{database}`.`role`'
|
144
|
+
),
|
145
|
+
'comment': 'Role information count.'
|
146
|
+
},
|
147
|
+
{
|
148
|
+
'name': 'perm_count',
|
149
|
+
'select': (
|
150
|
+
'SELECT COUNT(1)\n'
|
151
|
+
f'FROM `{database}`.`perm`'
|
152
|
+
),
|
153
|
+
'comment': 'Permission information count.'
|
154
|
+
},
|
155
|
+
{
|
156
|
+
'name': 'user_day_count',
|
157
|
+
'select': (
|
158
|
+
'SELECT COUNT(1)\n'
|
159
|
+
f'FROM `{database}`.`user`\n'
|
160
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) = 0'
|
161
|
+
),
|
162
|
+
'comment': 'User information count in the past day.'
|
163
|
+
},
|
164
|
+
{
|
165
|
+
'name': 'user_week_count',
|
166
|
+
'select': (
|
167
|
+
'SELECT COUNT(1)\n'
|
168
|
+
f'FROM `{database}`.`user`\n'
|
169
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 6'
|
170
|
+
),
|
171
|
+
'comment': 'User information count in the past week.'
|
172
|
+
},
|
173
|
+
{
|
174
|
+
'name': 'user_month_count',
|
175
|
+
'select': (
|
176
|
+
'SELECT COUNT(1)\n'
|
177
|
+
f'FROM `{database}`.`user`\n'
|
178
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 29'
|
179
|
+
),
|
180
|
+
'comment': 'User information count in the past month.'
|
181
|
+
},
|
182
|
+
{
|
183
|
+
'name': 'user_last_time',
|
184
|
+
'select': (
|
185
|
+
'SELECT MAX(`create_time`)\n'
|
186
|
+
f'FROM `{database}`.`user`'
|
187
|
+
),
|
188
|
+
'comment': 'User last record create time.'
|
189
|
+
}
|
190
|
+
]
|
191
|
+
}
|
192
|
+
]
|
193
|
+
|
194
|
+
# Build.
|
195
|
+
engine.sync_engine.build.build(tables=tables, views_stats=views_stats, skip=True)
|
196
|
+
|
197
|
+
|
198
|
+
auth_router = APIRouter()
|
199
|
+
depend_auth_sess = Bind.create_depend_db('auth', 'sess')
|
200
|
+
depend_auth_conn = Bind.create_depend_db('auth', 'conn')
|
201
|
+
|
202
|
+
|
203
|
+
@auth_router.post('/sessions')
|
204
|
+
async def create_sessions(
|
205
|
+
username: str = Bind.body,
|
206
|
+
password: str = Bind.body,
|
207
|
+
conn: Bind.Conn = depend_auth_conn
|
208
|
+
) -> dict:
|
209
|
+
"""
|
210
|
+
Create session.
|
211
|
+
|
212
|
+
Parameters
|
213
|
+
----------
|
214
|
+
username : User name.
|
215
|
+
password : User password.
|
216
|
+
|
217
|
+
Returns
|
218
|
+
-------
|
219
|
+
JSON with `token`.
|
220
|
+
"""
|
221
|
+
|
222
|
+
# Parameter.
|
223
|
+
key = ServerConfig.server.api_auth_key
|
224
|
+
password_hash = hash_bcrypt(password)
|
225
|
+
|
226
|
+
# Check.
|
227
|
+
sql = (
|
228
|
+
''
|
229
|
+
)
|
230
|
+
result = await conn.execute(
|
231
|
+
sql,
|
232
|
+
username=username,
|
233
|
+
password_hash=password_hash
|
234
|
+
)
|
235
|
+
|
236
|
+
# Check.
|
237
|
+
if result.empty:
|
238
|
+
exit_api(401)
|
239
|
+
|
240
|
+
# Response.
|
241
|
+
json = {
|
242
|
+
'time': now('timestamp'),
|
243
|
+
'sub': username,
|
244
|
+
'iat': now('timestamp'),
|
245
|
+
'nbf': now('timestamp'),
|
246
|
+
'exp': now('timestamp') + 28800000
|
247
|
+
}
|
248
|
+
token = encode_jwt(json, key)
|
249
|
+
data = {'token': token}
|
250
|
+
|
251
|
+
return data
|
reyserver/rfile.py
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
from fastapi import APIRouter
|
13
13
|
from fastapi.responses import FileResponse
|
14
|
-
from reydb import rorm
|
14
|
+
from reydb import rorm, DatabaseEngine, DatabaseEngineAsync
|
15
15
|
from reykit.ros import FileStore, get_md5
|
16
16
|
|
17
17
|
from .rbase import ServerConfig, Bind, exit_api
|
@@ -33,7 +33,7 @@ class DatabaseORMTableInfo(rorm.Model, table=True):
|
|
33
33
|
__name__ = 'info'
|
34
34
|
__comment__ = 'File information table.'
|
35
35
|
create_time: rorm.Datetime = rorm.Field(field_default=':create_time', not_null=True, index_n=True, comment='Record create time.')
|
36
|
-
file_id: int = rorm.Field(rorm.types_mysql.MEDIUMINT(unsigned=True), key_auto=True, comment='File
|
36
|
+
file_id: int = rorm.Field(rorm.types_mysql.MEDIUMINT(unsigned=True), key_auto=True, comment='File ID.')
|
37
37
|
md5: str = rorm.Field(rorm.types.CHAR(32), not_null=True, index_n=True, comment='File MD5.')
|
38
38
|
name: str = rorm.Field(rorm.types.VARCHAR(260), index_n=True, comment='File name.')
|
39
39
|
note: str = rorm.Field(rorm.types.VARCHAR(500), comment='File note.')
|
@@ -51,13 +51,16 @@ class DatabaseORMTableData(rorm.Model, table=True):
|
|
51
51
|
path: str = rorm.Field(rorm.types.VARCHAR(4095), not_null=True, comment='File disk storage path.')
|
52
52
|
|
53
53
|
|
54
|
-
def build_file_db() -> None:
|
54
|
+
def build_file_db(engine: DatabaseEngine | DatabaseEngineAsync) -> None:
|
55
55
|
"""
|
56
56
|
Check and build `file` database tables.
|
57
|
+
|
58
|
+
Parameters
|
59
|
+
----------
|
60
|
+
db : Database engine instance.
|
57
61
|
"""
|
58
62
|
|
59
63
|
# Set parameter.
|
60
|
-
engine = ServerConfig.server.db.file
|
61
64
|
database = engine.database
|
62
65
|
|
63
66
|
## Table.
|
@@ -179,7 +182,34 @@ depend_file_sess = Bind.create_depend_db('file', 'sess')
|
|
179
182
|
depend_file_conn = Bind.create_depend_db('file', 'conn')
|
180
183
|
|
181
184
|
|
182
|
-
@file_router.
|
185
|
+
@file_router.get('/files/{file_id}')
|
186
|
+
async def get_file_info(
|
187
|
+
file_id: int = Bind.path,
|
188
|
+
sess: Bind.Sess = depend_file_sess
|
189
|
+
) -> DatabaseORMTableInfo:
|
190
|
+
"""
|
191
|
+
Get file information.
|
192
|
+
|
193
|
+
Parameters
|
194
|
+
----------
|
195
|
+
file_id : File ID.
|
196
|
+
|
197
|
+
Returns
|
198
|
+
-------
|
199
|
+
File information.
|
200
|
+
"""
|
201
|
+
|
202
|
+
# Get.
|
203
|
+
table_info = await sess.get(DatabaseORMTableInfo, file_id)
|
204
|
+
|
205
|
+
# Check.
|
206
|
+
if table_info is None:
|
207
|
+
exit_api(404)
|
208
|
+
|
209
|
+
return table_info
|
210
|
+
|
211
|
+
|
212
|
+
@file_router.post('/files')
|
183
213
|
async def upload_file(
|
184
214
|
file: Bind.File = Bind.forms,
|
185
215
|
name: str = Bind.forms_n,
|
@@ -233,7 +263,7 @@ async def upload_file(
|
|
233
263
|
return table_info
|
234
264
|
|
235
265
|
|
236
|
-
@file_router.get('/{file_id}/download')
|
266
|
+
@file_router.get('/files/{file_id}/download')
|
237
267
|
async def download_file(
|
238
268
|
file_id: int = Bind.path,
|
239
269
|
conn: Bind.Conn = depend_file_conn
|
@@ -273,30 +303,3 @@ async def download_file(
|
|
273
303
|
response = FileResponse(file_path, filename=file_name)
|
274
304
|
|
275
305
|
return response
|
276
|
-
|
277
|
-
|
278
|
-
@file_router.get('/{file_id}')
|
279
|
-
async def get_file_info(
|
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
@@ -19,7 +19,8 @@ from fastapi.staticfiles import StaticFiles
|
|
19
19
|
from fastapi.middleware.gzip import GZipMiddleware
|
20
20
|
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
|
21
21
|
from reydb import DatabaseAsync
|
22
|
-
from reykit.rbase import
|
22
|
+
from reykit.rbase import CoroutineFunctionSimple, Singleton, throw
|
23
|
+
from reykit.rrand import randchar
|
23
24
|
|
24
25
|
from .rbase import ServerBase, ServerConfig, Bind
|
25
26
|
|
@@ -102,6 +103,8 @@ class Server(ServerBase, Singleton):
|
|
102
103
|
self.__add_default_middleware()
|
103
104
|
|
104
105
|
# API.
|
106
|
+
self.api_auth_key: str
|
107
|
+
'Authentication API JWT encryption key.'
|
105
108
|
self.api_file_dir: str
|
106
109
|
'File API store directory path.'
|
107
110
|
|
@@ -187,13 +190,30 @@ class Server(ServerBase, Singleton):
|
|
187
190
|
setattr(self.app, key, value)
|
188
191
|
|
189
192
|
|
190
|
-
def add_api_auth(self):
|
193
|
+
def add_api_auth(self, key: str | None = None) -> None:
|
191
194
|
"""
|
192
|
-
Add
|
195
|
+
Add authentication API.
|
193
196
|
Note: must include database engine of `auth` name.
|
197
|
+
|
198
|
+
Parameters
|
199
|
+
----------
|
200
|
+
key : JWT encryption key.
|
201
|
+
- `None`: Random 32 length string.
|
194
202
|
"""
|
195
203
|
|
196
|
-
|
204
|
+
from .rauth import build_file_db, auth_router
|
205
|
+
|
206
|
+
# Parameter.
|
207
|
+
if key is None:
|
208
|
+
key = randchar(32)
|
209
|
+
|
210
|
+
# Build database.
|
211
|
+
engine = self.db.auth
|
212
|
+
build_file_db(engine)
|
213
|
+
|
214
|
+
# Add.
|
215
|
+
self.api_auth_key = key
|
216
|
+
self.app.include_router(auth_router, tags=['auth'])
|
197
217
|
|
198
218
|
|
199
219
|
def add_api_file(self, file_dir: str = 'file') -> None:
|
@@ -207,11 +227,12 @@ class Server(ServerBase, Singleton):
|
|
207
227
|
prefix : File API path prefix.
|
208
228
|
"""
|
209
229
|
|
210
|
-
from .rfile import
|
230
|
+
from .rfile import build_file_db, file_router
|
211
231
|
|
212
232
|
# Build database.
|
213
|
-
|
233
|
+
engine = self.db.file
|
234
|
+
build_file_db(engine)
|
214
235
|
|
215
236
|
# Add.
|
216
237
|
self.api_file_dir = file_dir
|
217
|
-
self.app.include_router(file_router,
|
238
|
+
self.app.include_router(file_router, tags=['file'])
|
@@ -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=xknFI0IEMJcDRTkmO8jb-4Pbl7QSnQOA8m87D7gU3MM,9228
|
4
|
+
reyserver/rbase.py,sha256=IUVkkNsLmQh-QRLX6qtbCjPZAbQAsxoe0goPLCxG9KA,5283
|
5
|
+
reyserver/rclient.py,sha256=pTJtn78jPKgFo5EoQwZRdM0cYHdCs7QUKqfl-jUBRgk,4220
|
6
|
+
reyserver/rfile.py,sha256=RpMeq0vRStop4RnyjKv4wjdXgJjKPOAKpwPAKpLt0hk,9000
|
7
|
+
reyserver/rserver.py,sha256=oOfAc0aM-C561k8mKhF8_gYDmF0Kn6hKyZ5ff6mzPCE,6498
|
8
|
+
reyserver-1.1.50.dist-info/METADATA,sha256=iVbZ7pE_k0IlyYw1bsuw5lJIziRJ2CvsRyM4ivSQRi8,1689
|
9
|
+
reyserver-1.1.50.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
+
reyserver-1.1.50.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
11
|
+
reyserver-1.1.50.dist-info/RECORD,,
|
@@ -1,11 +0,0 @@
|
|
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,,
|
File without changes
|
File without changes
|