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.
@@ -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
- if 'request' in inspect.signature(request.fn).parameters:
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
- if 'app' in inspect.signature(fn).parameters:
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
- if static.scheduler_sync_servers:
383
- task = self.get_task(key)
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 (not task or task._queue.qsize()) or task.run_num_completed:
398
- break
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
- if 'app' in inspect.signature(fn).parameters:
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
- if static.scheduler_sync_servers:
439
- task = await self.async_get_task(key)
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
- if static.scheduler_sync_servers:
449
- sync_server = redis.asyncio.Redis(connection_pool = static.scheduler_sync_servers[1])
450
- await sync_server.hset('CheeseAPI_scheduler_tasks', key, json.dumps(task._to_dict()))
451
- await sync_server.hpexpire('CheeseAPI_scheduler_tasks', int(task.timeout * 1000), key)
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 (not task or task._queue.qsize()) or task.run_num_completed:
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 not task or task.auto_remove:
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
- redis.Redis(connection_pool = static.scheduler_sync_servers[0]).hdel('CheeseAPI_scheduler_tasks', task.key)
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 or not task.is_running:
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 or not task.is_running:
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
- return await fn(*args, **kwargs)
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
- if self.app.sync_server_url.startswith('redis'):
250
- pubsub = static.websocket_sync_server[self.websocket.request.path].pubsub()
251
- await pubsub.subscribe(self.websocket.request.path)
252
- async for message in pubsub.listen():
253
- if message['type'] != 'message':
254
- continue
255
-
256
- connectors = Websocket.connectors.get(self.websocket.request.path)
257
- if not connectors:
258
- continue
259
-
260
- message = message['data']
261
- if static.websocket_data_decode is not None:
262
- message = static.websocket_data_decode(message)
263
- message = json.loads(message.decode())
264
- if isinstance(message['key'], list):
265
- connectors = [connector for connector in connectors if connector.key in message['key']]
266
- elif isinstance(message['key'], str):
267
- connectors = [connector for connector in connectors if connector.key == message['key']]
268
- else:
269
- connectors = [connector for connector in connectors]
270
-
271
- if connectors:
272
- if message['event'] == 'send':
273
- for connector in connectors:
274
- asyncio.create_task(connector.send(message['data']))
275
- elif message['event'] == 'close':
276
- for connector in connectors:
277
- asyncio.create_task(connector.close())
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: CheeseAPI
3
- Version: 2.0.6b2
3
+ Version: 2.0.7
4
4
  Summary: 一款web协程框架
5
5
  Project-URL: Source, https://github.com/CheeseUnknown/CheeseAPI
6
6
  Author-email: Cheese Unknown <cheese@cheese.ren>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "CheeseAPI"
7
- version = "2.0.6-beta.2"
7
+ version = "2.0.7"
8
8
  description = "一款web协程框架"
9
9
  readme = "README.md"
10
10
  license-files = { paths = [ "LICENSE" ] }
File without changes
File without changes
File without changes
File without changes
File without changes