I tried to pass the sio instance to another class and send some calls from there to the client and when finished return back to the process_msg function.
But I guess since this is an async function, it won't work this way, I only get:
RuntimeWarning: coroutine 'AsyncServer.call' was never awaited
Is this even possible to emit or call from outside of the event handler? How could I accomplish something like this?
I've already tried and searched a lot, but couldn't find a solution.
Maybe this code helps to understand my problem:
import socketio
from aiohttp import web
class TestClass:
def __init__(self):
self.sio = socketio.AsyncServer(async_mode='aiohttp')
self.response_functions()
self.app = web.Application()
self.sio.attach(self.app)
web.run_app(self.app, host="0.0.0.0", port=5000, print=None, access_log=None)
def response_functions(self):
@self.sio.on("message")
async def process_msg(sid, msg):
ac = AnotherClass(self.sio, sid)
ac.do_some_action_here()
await self.sio.emit("my_event", "is_finished")
class AnotherClass:
def __init__(self, sio, sid):
self.sio = sio
self.sid = sid
def do_some_action_here(self):
# send some calls to the client, and wait to finish
self.sio.call("foo", "bar1", to=self.sid)
self.sio.call("foo", "bar2", to=self.sid)
self.sio.call("foo", "bar3", to=self.sid)
# return back to the event handler
TestClass()
Edit: It does work when I do the following:
async def process_msg(sid, msg):
ac = AnotherClass(self.sio, sid)
await ac.do_some_action_here()
await self.sio.emit("my_event", "is_finished")
async def do_some_action_here(self):
# send some calls to the client, and wait to finish
await self.sio.call("foo", "bar1", to=self.sid)
But unfortunately this is not an option for me because in my real code there are a dozen of other functions and classes before. I would like to set a method in a singleton threading helper class, which I can access from all over my code to send events to the client before the event is complete finished.
Edit 2:
I've finally found a way to accomplish what I need. I just need to run the "AnotherClass" in a separated thread and get the event loop, this way I can do some other stuff and still call the client and wait for an answer.
Thanks @Miguel Grinberg for the hint with "Mixing sync and async code", this made me think and I could find another solution and also got a bit more experience with async code.
Here my final example in case someone else needs a similar solution:
import socketio
from aiohttp import web
import asyncio
from threading import Thread
class TestClass:
def __init__(self):
self.sio = socketio.AsyncServer(async_mode='aiohttp')
self.response_functions()
self.app = web.Application()
self.sio.attach(self.app)
web.run_app(self.app, host="0.0.0.0", port=5000, print=None, access_log=None)
def response_functions(self):
@self.sio.on("message")
async def process_msg(sid, msg):
server_loop = asyncio.get_event_loop()
AnotherClass(self.sio, sid, server_loop).start()
class AnotherClass(Thread):
def __init__(self, sio, sid, server_loop):
super(AnotherClass, self).__init__(daemon=True)
self.sio = sio
self.sid = sid
self.server_loop = server_loop
def run(self):
# Do some calls and wait for each call to finish
self.handler("foo", "bar1")
self.handler("foo", "bar2")
self.handler("foo", "bar3")
def handler(self, event, msg):
async def send(event, msg):
await self.sio.call(event, msg, to=self.sid)
asyncio.run_coroutine_threadsafe(send(event, msg), self.server_loop).result()
TestClass()