CheeseAPI 2.0.6b2__tar.gz → 2.0.7__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.
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/app.py +2 -1
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/scheduler.py +38 -67
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/validator.py +7 -5
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/websocket.py +38 -30
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/PKG-INFO +1 -1
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/pyproject.toml +1 -1
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/.gitignore +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/__init__.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/cors.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/file.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/printer.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/request.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/response.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/route.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/signal.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/CheeseAPI/static.py +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/LICENSE +0 -0
- {cheeseapi-2.0.6b2 → cheeseapi-2.0.7}/README.md +0 -0
|
@@ -334,7 +334,8 @@ class AppProxy:
|
|
|
334
334
|
async def get_response(self, request: Request) -> Response:
|
|
335
335
|
if inspect.isfunction(request.fn):
|
|
336
336
|
try:
|
|
337
|
-
|
|
337
|
+
signature = inspect.signature(request.fn)
|
|
338
|
+
if 'request' in signature.parameters or any(p.kind == inspect.Parameter.VAR_KEYWORD for p in signature.parameters.values()):
|
|
338
339
|
return await request.fn(request = request)
|
|
339
340
|
else:
|
|
340
341
|
return await request.fn()
|
|
@@ -242,6 +242,7 @@ class SchedulerProxy:
|
|
|
242
242
|
|
|
243
243
|
def __setstate__(self, state):
|
|
244
244
|
self.app = state[1]['app']
|
|
245
|
+
self._tasks = {}
|
|
245
246
|
|
|
246
247
|
def init(self, app = None):
|
|
247
248
|
if not app:
|
|
@@ -257,11 +258,11 @@ class SchedulerProxy:
|
|
|
257
258
|
coro.close()
|
|
258
259
|
|
|
259
260
|
def _start_pubsub(self, app: 'CheeseAPI'):
|
|
260
|
-
pubsub = redis.Redis(connection_pool = static.scheduler_sync_servers[0]).pubsub()
|
|
261
|
-
pubsub.subscribe('CheeseAPI_scheduler')
|
|
262
261
|
try:
|
|
263
262
|
while True:
|
|
264
263
|
try:
|
|
264
|
+
pubsub = redis.Redis(connection_pool = static.scheduler_sync_servers[0]).pubsub()
|
|
265
|
+
pubsub.subscribe('CheeseAPI_scheduler')
|
|
265
266
|
for message in pubsub.listen():
|
|
266
267
|
if message['type'] == 'message':
|
|
267
268
|
data = json.loads(message['data'])
|
|
@@ -277,9 +278,7 @@ class SchedulerProxy:
|
|
|
277
278
|
elif data[0] == 'remove':
|
|
278
279
|
self.remove(data[1])
|
|
279
280
|
except redis.exceptions.RedisError:
|
|
280
|
-
pubsub.close()
|
|
281
281
|
time.sleep(app.sync_server_timeout)
|
|
282
|
-
self._start_pubsub(app)
|
|
283
282
|
except (KeyboardInterrupt, SystemExit):
|
|
284
283
|
...
|
|
285
284
|
|
|
@@ -352,111 +351,80 @@ class SchedulerProxy:
|
|
|
352
351
|
|
|
353
352
|
def task_processing(self, key: str, queue: multiprocessing.Queue, fn, *args, **kwargs):
|
|
354
353
|
try:
|
|
355
|
-
task = self.get_task(key)
|
|
356
|
-
if not task:
|
|
357
|
-
return
|
|
358
|
-
|
|
359
354
|
queue.get()
|
|
360
|
-
task._queue.get()
|
|
361
|
-
first_run = True
|
|
362
355
|
|
|
356
|
+
task = self.get_task(key)
|
|
357
|
+
if static.scheduler_sync_servers:
|
|
358
|
+
task._queue.get()
|
|
363
359
|
if task.first_run_timer:
|
|
364
360
|
time.sleep(max(0, task.first_run_timer.timestamp() - time.time()))
|
|
365
361
|
|
|
366
362
|
while not queue.qsize():
|
|
367
|
-
if static.scheduler_sync_servers:
|
|
368
|
-
task = self.get_task(key)
|
|
369
|
-
if (not task or (not first_run and task._queue.qsize())):
|
|
370
|
-
break
|
|
371
|
-
|
|
372
363
|
now = time.time()
|
|
373
364
|
|
|
374
365
|
try:
|
|
375
|
-
|
|
366
|
+
signature = inspect.signature(fn)
|
|
367
|
+
has_kwargs = any(p.kind == inspect.Parameter.VAR_KEYWORD for p in signature.parameters.values())
|
|
368
|
+
if 'app' in signature.parameters or has_kwargs:
|
|
376
369
|
fn(*args, app = self.app, **kwargs)
|
|
377
370
|
else:
|
|
378
371
|
fn(*args, **kwargs)
|
|
379
372
|
except Exception as e:
|
|
380
373
|
self.app.printer.scheduler_error(e, task)
|
|
381
374
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
if task:
|
|
386
|
-
if first_run:
|
|
387
|
-
task._queue.get()
|
|
388
|
-
task._last_run_time = time.time() - now
|
|
389
|
-
task._last_run_timer = datetime.datetime.fromtimestamp(now)
|
|
390
|
-
task._run_num += 1
|
|
391
|
-
|
|
392
|
-
if static.scheduler_sync_servers:
|
|
393
|
-
sync_server = redis.Redis(connection_pool = static.scheduler_sync_servers[0])
|
|
394
|
-
sync_server.hset('CheeseAPI_scheduler_tasks', key, json.dumps(task._to_dict()))
|
|
395
|
-
sync_server.hpexpire('CheeseAPI_scheduler_tasks', int(task.timeout * 1000), key)
|
|
375
|
+
task._last_run_time = time.time() - now
|
|
376
|
+
task._last_run_timer = datetime.datetime.fromtimestamp(now)
|
|
377
|
+
task._run_num += 1
|
|
396
378
|
|
|
397
|
-
if
|
|
398
|
-
|
|
379
|
+
if static.scheduler_sync_servers:
|
|
380
|
+
sync_server = redis.Redis(connection_pool = static.scheduler_sync_servers[0])
|
|
381
|
+
sync_server.hset('CheeseAPI_scheduler_tasks', key, json.dumps(task._to_dict()))
|
|
382
|
+
sync_server.hpexpire('CheeseAPI_scheduler_tasks', int(task.timeout * 1000), key)
|
|
399
383
|
|
|
400
|
-
first_run = False
|
|
401
384
|
time.sleep(max(0, task.interval_time - time.time() + now))
|
|
402
385
|
except (KeyboardInterrupt, SystemExit):
|
|
403
386
|
...
|
|
404
387
|
|
|
405
|
-
queue.put(None)
|
|
406
|
-
|
|
407
388
|
if static.scheduler_sync_servers and task:
|
|
408
389
|
redis.Redis(connection_pool = static.scheduler_sync_servers[0]).hpersist('CheeseAPI_scheduler_tasks', key)
|
|
409
390
|
|
|
410
391
|
async def async_task_processing(self, key: str, queue: multiprocessing.Queue, fn, *args, **kwargs):
|
|
411
|
-
task = self.get_task(key)
|
|
412
|
-
if not task:
|
|
413
|
-
return
|
|
414
|
-
|
|
415
392
|
queue.get()
|
|
416
|
-
task._queue.get()
|
|
417
|
-
first_run = True
|
|
418
393
|
|
|
394
|
+
task = await self.async_get_task(key)
|
|
395
|
+
if static.scheduler_sync_servers:
|
|
396
|
+
task._queue.get()
|
|
419
397
|
if task.first_run_timer:
|
|
420
398
|
await asyncio.sleep(max(0, task.first_run_timer.timestamp() - time.time()))
|
|
421
399
|
|
|
422
400
|
while not queue.qsize():
|
|
423
|
-
if static.scheduler_sync_servers:
|
|
424
|
-
task = await self.async_get_task(key)
|
|
425
|
-
if (not task or (not first_run and task._queue.qsize())):
|
|
426
|
-
break
|
|
427
|
-
|
|
428
401
|
now = time.time()
|
|
429
402
|
|
|
430
403
|
try:
|
|
431
|
-
|
|
404
|
+
signature = inspect.signature(fn)
|
|
405
|
+
has_kwargs = any(p.kind == inspect.Parameter.VAR_KEYWORD for p in signature.parameters.values())
|
|
406
|
+
if 'app' in signature.parameters or has_kwargs:
|
|
432
407
|
await fn(*args, app = self.app, **kwargs)
|
|
433
408
|
else:
|
|
434
409
|
await fn(*args, **kwargs)
|
|
435
410
|
except Exception as e:
|
|
436
411
|
self.app.printer.scheduler_error(e, task)
|
|
437
412
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
if task:
|
|
442
|
-
if first_run:
|
|
443
|
-
task._queue.get()
|
|
444
|
-
task._last_run_time = time.time() - now
|
|
445
|
-
task._last_run_timer = datetime.datetime.fromtimestamp(now)
|
|
446
|
-
task._run_num += 1
|
|
413
|
+
task._last_run_time = time.time() - now
|
|
414
|
+
task._last_run_timer = datetime.datetime.fromtimestamp(now)
|
|
415
|
+
task._run_num += 1
|
|
447
416
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
417
|
+
if static.scheduler_sync_servers:
|
|
418
|
+
sync_server = redis.asyncio.Redis(connection_pool = static.scheduler_sync_servers[1])
|
|
419
|
+
await sync_server.hset('CheeseAPI_scheduler_tasks', key, json.dumps(task._to_dict()))
|
|
420
|
+
await sync_server.hpexpire('CheeseAPI_scheduler_tasks', int(task.timeout * 1000), key)
|
|
452
421
|
|
|
453
|
-
if
|
|
422
|
+
if task.run_num_completed:
|
|
454
423
|
break
|
|
455
424
|
|
|
456
|
-
first_run = False
|
|
457
425
|
await asyncio.sleep(max(0, task.interval_time - time.time() + now))
|
|
458
426
|
|
|
459
|
-
if
|
|
427
|
+
if task.auto_remove:
|
|
460
428
|
self._tasks.pop(key, None)
|
|
461
429
|
if static.scheduler_sync_servers is not None:
|
|
462
430
|
await redis.asyncio.Redis(connection_pool = static.scheduler_sync_servers[1]).hdel('CheeseAPI_scheduler_tasks', key)
|
|
@@ -470,7 +438,8 @@ class SchedulerProxy:
|
|
|
470
438
|
elif task.run_type == 'PROCESS' and isinstance(task._handler, multiprocessing.Process):
|
|
471
439
|
task._handler.join()
|
|
472
440
|
self._tasks.pop(task.key, None)
|
|
473
|
-
|
|
441
|
+
if static.scheduler_sync_servers:
|
|
442
|
+
redis.Redis(connection_pool = static.scheduler_sync_servers[0]).hdel('CheeseAPI_scheduler_tasks', task.key)
|
|
474
443
|
|
|
475
444
|
def start(self, key: str):
|
|
476
445
|
task = self.get_task(key)
|
|
@@ -504,7 +473,7 @@ class SchedulerProxy:
|
|
|
504
473
|
if not task and static.scheduler_sync_servers:
|
|
505
474
|
await redis.asyncio.Redis(connection_pool = static.scheduler_sync_servers[1]).publish('CheeseAPI_scheduler', json.dumps(['start', key]))
|
|
506
475
|
else:
|
|
507
|
-
task._handler = asyncio.create_task(self.async_task_processing(task, *task.args, **task.kwargs))
|
|
476
|
+
task._handler = asyncio.create_task(self.async_task_processing(key, task._queue, task.fn, *task.args, **task.kwargs))
|
|
508
477
|
|
|
509
478
|
def stop(self, key: str):
|
|
510
479
|
task = self.get_task(key)
|
|
@@ -524,7 +493,7 @@ class SchedulerProxy:
|
|
|
524
493
|
|
|
525
494
|
def remove(self, key: str):
|
|
526
495
|
task = self.get_task(key)
|
|
527
|
-
if not task
|
|
496
|
+
if not task:
|
|
528
497
|
return
|
|
529
498
|
|
|
530
499
|
_task = self._tasks.get(key)
|
|
@@ -532,6 +501,7 @@ class SchedulerProxy:
|
|
|
532
501
|
if static.scheduler_sync_servers:
|
|
533
502
|
redis.Redis(connection_pool = static.scheduler_sync_servers[0]).publish('CheeseAPI_scheduler', json.dumps(['remove', key]))
|
|
534
503
|
else:
|
|
504
|
+
_task._queue.put(None)
|
|
535
505
|
self._tasks.pop(key, None)
|
|
536
506
|
if static.scheduler_sync_servers:
|
|
537
507
|
redis.Redis(connection_pool = static.scheduler_sync_servers[0]).hdel('CheeseAPI_scheduler_tasks', key)
|
|
@@ -554,7 +524,7 @@ class SchedulerProxy:
|
|
|
554
524
|
|
|
555
525
|
async def async_remove(self, key: str):
|
|
556
526
|
task = await self.async_get_task(key)
|
|
557
|
-
if not task
|
|
527
|
+
if not task:
|
|
558
528
|
return
|
|
559
529
|
|
|
560
530
|
_task = self._tasks.get(key)
|
|
@@ -562,6 +532,7 @@ class SchedulerProxy:
|
|
|
562
532
|
if static.scheduler_sync_servers:
|
|
563
533
|
await redis.asyncio.Redis(connection_pool = static.scheduler_sync_servers[1]).publish('CheeseAPI_scheduler', json.dumps(['remove', key]))
|
|
564
534
|
else:
|
|
535
|
+
_task._queue.put(None)
|
|
565
536
|
self._tasks.pop(key, None)
|
|
566
537
|
if static.scheduler_sync_servers:
|
|
567
538
|
await redis.asyncio.Redis(connection_pool = static.scheduler_sync_servers[1]).hdel('CheeseAPI_scheduler_tasks', key)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import json
|
|
1
|
+
import json, inspect
|
|
2
2
|
from typing import Callable, TYPE_CHECKING
|
|
3
3
|
from functools import wraps
|
|
4
4
|
|
|
@@ -20,10 +20,8 @@ def validator(*, json_model: pydantic.BaseModel | None = None, form_model: pydan
|
|
|
20
20
|
|
|
21
21
|
def wrapper(fn: Callable) -> Callable:
|
|
22
22
|
@wraps(fn)
|
|
23
|
-
async def decorator(*args, **kwargs):
|
|
23
|
+
async def decorator(*args, request: 'Request', **kwargs):
|
|
24
24
|
try:
|
|
25
|
-
request: 'Request' = kwargs.get('request', None)
|
|
26
|
-
|
|
27
25
|
json_data = None
|
|
28
26
|
if json_model is not None:
|
|
29
27
|
json_data = json_model.model_validate(request.json or {}, by_alias = True)
|
|
@@ -59,6 +57,10 @@ def validator(*, json_model: pydantic.BaseModel | None = None, form_model: pydan
|
|
|
59
57
|
else:
|
|
60
58
|
return Response(json.loads(e.json()), 400)
|
|
61
59
|
|
|
62
|
-
|
|
60
|
+
signature = inspect.signature(fn)
|
|
61
|
+
if 'request' in signature.parameters or any(p.kind == inspect.Parameter.VAR_KEYWORD for p in signature.parameters.values()):
|
|
62
|
+
return await fn(*args, request = request, **kwargs)
|
|
63
|
+
else:
|
|
64
|
+
return await fn(*args, **kwargs)
|
|
63
65
|
return decorator
|
|
64
66
|
return wrapper
|
|
@@ -2,7 +2,7 @@ import base64, hashlib, asyncio, ssl, struct, json
|
|
|
2
2
|
from functools import partial
|
|
3
3
|
from typing import TYPE_CHECKING, AsyncIterable, Self
|
|
4
4
|
|
|
5
|
-
import redis
|
|
5
|
+
import redis, redis.exceptions
|
|
6
6
|
|
|
7
7
|
from CheeseAPI import static
|
|
8
8
|
from CheeseAPI.response import Response
|
|
@@ -246,35 +246,43 @@ class WebsocketProxy:
|
|
|
246
246
|
await self.websocket.on_connect()
|
|
247
247
|
|
|
248
248
|
async def sync_server_running(self):
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
249
|
+
try:
|
|
250
|
+
if self.app.sync_server_url.startswith('redis'):
|
|
251
|
+
while True:
|
|
252
|
+
try:
|
|
253
|
+
pubsub = static.websocket_sync_server[self.websocket.request.path].pubsub()
|
|
254
|
+
await pubsub.subscribe(self.websocket.request.path)
|
|
255
|
+
async for message in pubsub.listen():
|
|
256
|
+
print(message)
|
|
257
|
+
if message['type'] != 'message':
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
connectors = Websocket.connectors.get(self.websocket.request.path)
|
|
261
|
+
if not connectors:
|
|
262
|
+
continue
|
|
263
|
+
|
|
264
|
+
message = message['data']
|
|
265
|
+
if static.websocket_data_decode is not None:
|
|
266
|
+
message = static.websocket_data_decode(message)
|
|
267
|
+
message = json.loads(message.decode())
|
|
268
|
+
if isinstance(message['key'], list):
|
|
269
|
+
connectors = [connector for connector in connectors if connector.key in message['key']]
|
|
270
|
+
elif isinstance(message['key'], str):
|
|
271
|
+
connectors = [connector for connector in connectors if connector.key == message['key']]
|
|
272
|
+
else:
|
|
273
|
+
connectors = [connector for connector in connectors]
|
|
274
|
+
|
|
275
|
+
if connectors:
|
|
276
|
+
if message['event'] == 'send':
|
|
277
|
+
for connector in connectors:
|
|
278
|
+
asyncio.create_task(connector.send(message['data']))
|
|
279
|
+
elif message['event'] == 'close':
|
|
280
|
+
for connector in connectors:
|
|
281
|
+
asyncio.create_task(connector.close())
|
|
282
|
+
except redis.exceptions.RedisError:
|
|
283
|
+
await asyncio.sleep(self.app.sync_server_timeout)
|
|
284
|
+
except (KeyboardInterrupt, SystemExit, asyncio.CancelledError):
|
|
285
|
+
...
|
|
278
286
|
|
|
279
287
|
async def message(self):
|
|
280
288
|
while True:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|