PNG IHDR x sBIT|d pHYs + tEXtSoftware www.inkscape.org< ,tEXtComment
import asyncio
import logging
import threading
import time
import traceback
from pyroute2 import config
from . import schema
from .events import (
DBMExitException,
InvalidateHandlerException,
RescheduleException,
ShutdownException,
State,
)
from .messages import cmsg_event, cmsg_failed
log = logging.getLogger(__name__)
class TaskAdapter:
def __init__(self):
self.event = asyncio.Event()
self.state = State()
class Task:
def __init__(self, coro, target_state, obj):
self.exception = None
self.coro = coro
self.target_state = target_state
self.obj = obj if obj is not None else TaskAdapter()
self.restart()
def restart(self):
self.task = asyncio.create_task(self.coro())
self.obj.task_id = id(self.task)
def commit(self):
self.exception = self.task.exception()
@property
def event(self):
return self.obj.event
@property
def state(self):
return self.obj.state
@property
def task_id(self):
return id(self.task)
class TaskManager:
def __init__(self, ndb):
self.ndb = ndb
self.log = ndb.log
self.event_map = {}
self.task_map = {}
self.event_queue = asyncio.Queue()
self.stop_event = asyncio.Event()
self.reload_event = asyncio.Event()
self.thread = None
self.ctime = self.gctime = time.time()
def register_handler(self, event, handler):
if event not in self.event_map:
self.event_map[event] = []
self.event_map[event].append(handler)
def unregister_handler(self, event, handler):
self.event_map[event].remove(handler)
async def handler_default(self, sources, target, event):
if isinstance(getattr(event, 'payload', None), Exception):
raise event.payload
log.debug('unsupported event ignored: %s' % type(event))
async def handler_event(self, sources, target, event):
event.payload.set()
async def handler_failed(self, sources, target, event):
self.ndb.schema.mark(target, 1)
def create_task(self, coro, state='running', obj=None):
task = Task(coro, state, obj)
self.task_map[task.task_id] = task
self.reload_event.set()
return task
def restart_task(self, task):
task.restart()
self.task_map[task.task_id] = task
self.reload_event.set()
return task
async def stop(self):
await self.stop_event.wait()
async def reload(self):
await self.reload_event.wait()
async def task_watch(self):
while True:
tasks = list([x.task for x in self.task_map.values()])
done, pending = await asyncio.wait(
tasks, return_when=asyncio.FIRST_COMPLETED
)
self.log.debug(f'task done {done}')
if self.stop_event.is_set():
return
for t in done:
task = self.task_map.pop(id(t))
task.commit()
if task.target_state == 'running':
self.restart_task(task)
self.reload_event.clear()
async def receiver(self):
while True:
event = await self.event_queue.get()
reschedule = []
handlers = self.event_map.get(
event.__class__, [self.handler_default]
)
for handler in tuple(handlers):
try:
target = event['header']['target']
# self.log.debug(f'await {handler} for {event}')
await handler(self.ndb.sources.asyncore, target, event)
except RescheduleException:
if 'rcounter' not in event['header']:
event['header']['rcounter'] = 0
if event['header']['rcounter'] < 3:
event['header']['rcounter'] += 1
self.log.debug('reschedule %s' % (event,))
reschedule.append(event)
else:
self.log.error('drop %s' % (event,))
except InvalidateHandlerException:
try:
handlers.remove(handler)
except Exception:
self.log.error(
'could not invalidate '
'event handler:\n%s' % traceback.format_exc()
)
except ShutdownException:
return
except DBMExitException:
return
except Exception:
self.log.error(
'could not load event:\n%s\n%s'
% (event, traceback.format_exc())
)
if time.time() - self.gctime > config.gc_timeout:
self.gctime = time.time()
def setup(self):
self.thread = id(threading.current_thread())
event_map = {
cmsg_event: [self.handler_event],
cmsg_failed: [self.handler_failed],
}
self.event_map = event_map
self.ndb.schema = schema.DBSchema(
self.ndb.config, self.event_map, self.log.channel('schema')
)
for event, handlers in self.ndb.schema.event_map.items():
for handler in handlers:
self.register_handler(event, handler)
async def run(self):
self.event_loop = asyncio.get_event_loop()
self.ndb.event_loop = self.event_loop
self.create_task(self.receiver)
self.create_task(self.stop)
self.create_task(self.reload)
self.ndb._dbm_ready.set()
await self.task_watch()
def cleanup(self):
self.ndb.schema.close()
self.ndb._dbm_shutdown.set()
def main(self):
try:
self.setup()
except Exception as e:
self.ndb._dbm_error = e
self.ndb._dbm_ready.set()
return
asyncio.run(self.run())
self.cleanup()
b IDATxytVսϓ22 A@IR:hCiZ[v*E:WũZA ^dQeQ @ !jZ'>gsV仿$|?g)&x-E