socketify.py/src/socketify/loop.py

143 wiersze
4.1 KiB
Python
Czysty Zwykły widok Historia

import asyncio
import logging
2022-11-01 13:22:55 +00:00
from .uv import UVLoop
2022-11-14 19:11:08 +00:00
import asyncio
2022-05-31 20:53:20 +00:00
def future_handler(future, loop, exception_handler, response):
try:
future.result()
return None
except Exception as error:
2022-11-16 19:28:46 +00:00
if hasattr(exception_handler, "__call__"):
2022-05-31 20:53:20 +00:00
exception_handler(loop, error, response)
else:
try:
2022-11-16 19:28:46 +00:00
# just log in console the error to call attention
logging.error("Uncaught Exception: %s" % str(error))
2022-05-31 20:53:20 +00:00
if response != None:
response.write_status(500).end("Internal Error")
finally:
return None
return None
2022-05-31 20:53:20 +00:00
2022-11-16 19:28:46 +00:00
class Loop:
2022-05-31 20:53:20 +00:00
def __init__(self, exception_handler=None):
self.loop = asyncio.new_event_loop()
self.uv_loop = UVLoop()
2022-11-16 19:28:46 +00:00
if hasattr(exception_handler, "__call__"):
2022-05-31 20:53:20 +00:00
self.exception_handler = exception_handler
2022-11-16 19:28:46 +00:00
self.loop.set_exception_handler(
lambda loop, context: exception_handler(loop, context, None)
)
2022-05-31 20:53:20 +00:00
else:
self.exception_handler = None
asyncio.set_event_loop(self.loop)
self.started = False
self.last_defer = False
2022-10-25 12:53:18 +00:00
def set_timeout(self, timeout, callback, user_data):
return self.uv_loop.create_timer(timeout, 0, callback, user_data)
def create_future(self):
return self.loop.create_future()
def start(self):
self.started = True
2022-11-16 19:28:46 +00:00
# run asyncio once per tick
def tick(loop):
2022-11-16 19:28:46 +00:00
# run once asyncio
2022-11-06 10:22:10 +00:00
loop.run_once_asyncio()
2022-11-16 19:28:46 +00:00
# use check for calling asyncio once per tick
2022-11-06 10:25:07 +00:00
self.timer = self.uv_loop.create_timer(0, 1, tick, self)
# self.timer = self.uv_loop.create_check(tick, self)
def run(self):
self.uv_loop.run()
def run_once(self):
self.uv_loop.run_once()
def run_once_asyncio(self):
# with suppress(asyncio.CancelledError):
2022-11-16 19:28:46 +00:00
# run only one step
self.loop.call_soon(self.loop.stop)
self.loop.run_forever()
def stop(self):
2022-11-16 19:28:46 +00:00
if self.started:
self.timer.stop()
self.started = False
2022-11-16 19:28:46 +00:00
# unbind run_once
# if is still running stops
if self.loop.is_running():
self.loop.stop()
self.last_defer = None
# Find all running tasks in main thread:
pending = asyncio.all_tasks(self.loop)
# Run loop until tasks done
self.loop.run_until_complete(asyncio.gather(*pending))
2022-11-16 19:28:46 +00:00
# Exposes native loop for uWS
def get_native_loop(self):
return self.uv_loop.get_native_loop()
2022-05-31 20:53:20 +00:00
def run_async(self, task, response=None):
2022-11-16 19:28:46 +00:00
# with run_once
future = asyncio.ensure_future(task, loop=self.loop)
2022-11-16 19:28:46 +00:00
# with threads
future.add_done_callback(
lambda f: future_handler(f, self.loop, self.exception_handler, response)
)
# force asyncio run once to enable req in async functions before first await
self.run_once_asyncio()
2022-10-24 17:15:46 +00:00
2022-11-16 19:28:46 +00:00
# if response != None: #set auto cork
# response.needs_cork = True
2022-05-31 20:53:20 +00:00
return future
2022-06-01 23:00:05 +00:00
# if sys.version_info >= (3, 11)
# with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner:
# runner.run(main())
# else:
# uvloop.install()
2022-11-14 19:11:08 +00:00
# asyncio.run(main())
2022-11-16 19:28:46 +00:00
# see ./native/uv_selector.txt
2022-11-15 13:17:09 +00:00
# will only work on linux and macos
2022-11-14 19:11:08 +00:00
# class UVSelector(asyncio.SelectorEventLoop):
2022-11-15 13:17:09 +00:00
# def register(self, fileobj, events, data=None):
# fd = fileobj.fileno()
# if fd == -1:
# return None
# mask = int(events)
# selector_key = (fs, mask, data)
# pass
2022-11-14 19:11:08 +00:00
# def tick(self):
# pass
# # We expose our own event loop for use with asyncio
# class AsyncioUVLoop(asyncio.SelectorEventLoop):
# def __init__(self):
# self.selector = UVSelector()
# super().__init__(self.selector)
# def call_soon(self, *args, **kwargs):
# self.selector.tick()
# return super().call_soon(*args, **kwargs)
# def call_at(self, *args, **kwargs):
# self.selector.tick()
# return super().call_at(*args, **kwargs)
# asyncio.set_event_loop(uws.Loop())
# asyncio.get_event_loop().run_forever()