Целью является создание приложения, которое обрабатывает данные с WebSocket и CAN-шины.
Я использую websockets, который является асинхронным, но библиотека python-can синхронизируется, и именно здесь начинаются проблемы.
Единственный способ, который я понял, - это использовать декораторы, которые преобразуют функции синхронизации в асинхронные и наоборот.
В упрощенном примере ниже: сервер получает сообщение по шине can -> сервер отправляет сообщение на ws.
WebSocket.py:
async def websocket_handler(websocket, path):
# ...
async def send(data):
await client.send(json.dumps(data))
def init():
return websockets.serve(websocket_handler, 'localhost', 6969)
CAN.py:
_bus = None
@force_sync
async def on_message_received(msg):
# ...
await WebSocket.send(...)
@force_async
def handle_messages():
while True:
msg = _bus.recv()
if msg is not None:
print(msg)
on_message_received(msg)
async def init():
global _bus
_bus = Bus('test', bustype='virtual')
await handle_messages()
декораторы:
def force_async(fn):
pool = ThreadPoolExecutor()
def wrapper(*args, **kwargs):
future = pool.submit(fn, *args, **kwargs)
return asyncio.wrap_future(future)
return wrapper
def force_sync(fn):
def wrapper(*args, **kwargs):
res = fn(*args, **kwargs)
if asyncio.iscoroutine(res):
return asyncio.new_event_loop().run_until_complete(res)
return res
return wrapper
main.py:
asyncio.get_event_loop().run_until_complete(asyncio.gather(
CAN.init(),
WebSocket.init(),
can_test.init()
))
asyncio.get_event_loop().run_forever()
Я новичок в Python, но выглядит ужасно неправильно. Есть ли правильный способ сделать это?