Issue
I am trying to emulate the reading of a NFC chip by pressing the cmd key in a little python script that acts as a socket-io server. It's job is to notify a client after the cmd key has been pressed. It works, but emulate_nfc_tag()
takes ages to execute after i press cmd. I suspect it has to do with how create_task works. I hope someone can spot how i could optimize this code.
from aiohttp import web
import socketio
import asyncio
from pynput import keyboard
import random
import string
sio = socketio.AsyncServer(cors_allowed_origins='*',
async_mode='aiohttp')
app = web.Application()
sio.attach(app)
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
async def emulate_nfc_tag():
print("sending out nfc id")
await sio.emit("nfc", id_generator())
def on_press(key):
if key == keyboard.Key.shift:
print("here we go")
loop.create_task(emulate_nfc_tag())
if key == keyboard.Key.esc:
# Stop listener
return False
async def index(request):
"""Serve the client-side application."""
with open('../client/dist/index.html') as f:
return web.Response(text=f.read(), content_type='text/html')
@sio.event
def connect(sid, environ):
print("connect ", sid)
@sio.event
def disconnect(sid):
print('disconnect ', sid)
@sio.event
async def msg(sid, data):
print('message ', data)
await sio.emit("msg", "Hi back")
app.router.add_static('/assets', '../client/dist/assets')
app.router.add_get('/', index)
if __name__ == '__main__':
# web.run_app(app)
loop = asyncio.get_event_loop()
listener = keyboard.Listener(on_press=on_press)
listener.start()
# set up aiohttp - like run_app, but non-blocking
runner = web.AppRunner(app)
loop.run_until_complete(runner.setup())
site = web.TCPSite(runner)
loop.run_until_complete(site.start())
# add more stuff to the loop
loop.run_forever()
Solution
The handlers that you configure for your keyboard run on a background thread and not in the thread that holds your asyncio application. You are calling the create_task()
function from this handler, which is invalid because this function must be called from the asyncio thread.
Instead, you may want to try with the run_coroutine_threadsafe(), which is specifically designed for your use case in which you want to start a coroutine in the asyncio thread, but doing it from another thread.
Answered By - Miguel Grinberg
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.