miguelgrinberg / python-socketio

Python Socket.IO server and client
MIT License
4k stars 588 forks source link

How to access server instance from inside an event handler #354

Closed ghost closed 5 years ago

ghost commented 5 years ago

` server = SIOServer()

@server.service.on('get_bananas', namespace="/namespace1")
async def some_request_1(sid=None, data=None):
    #server.service.enter_room(sid, f'user__{sid}')
    print(f'EMITING server_response WITH SID {sid} and namespace /namespace1')

    await server.service.emit('server_response', {}, namespace='/namespace1')
    # BUT server IS NOT DEFINED ?????

    #server.service.leave_room(sid, f'user__{sid}')

server.start_service()
async_to_sync(server.service.emit)('server_response', {}, namespace='/namespace1')

`

I'm trying to respond from the server by emitting something inside the event handler. That means client-says-something ----> triggers-event-in-server ----> server-emits-to-all

But I am unable to access the server instance from inside the handler. How can I get access to it ? Is there any special variable ? I've been unable to find a suitable example for this.

miguelgrinberg commented 5 years ago

If you are getting errors, please include the output that you are getting including the stack trace please.

ghost commented 5 years ago

Hi, here's the full output:

Started ServiceMonitor for WebsocketService ... Started on localhost:29000 ======== Running on http://localhost:29000 ======== (Press CTRL+C to quit) Traceback (most recent call last): EMITING server_response WITH SID d146c7dfc0f148f6b55f7d4ff8a1a71f and namespace /namespace1 File "/Users/john/Desktop/simplechat.py", line 70, in async_to_sync(sio_client.emit)('get_bananas', {}, namespace='/namespace1') File "/usr/local/lib/python3.7/site-packages/asgiref/sync.py", line 116, in call return call_result.result() File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 428, in result return self.get_result() File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 384, in get_result raise self._exception File "/usr/local/lib/python3.7/site-packages/asgiref/sync.py", line 156, in main_wrap result = await self.awaitable(*args, **kwargs) TypeError: object NoneType can't be used in 'await' expression

It says server is NoneType.

My server init is something like this: self.service = socketio.AsyncServer() self.webserver = web.Application() . #aiohttp.web self.service.attach(self.webserver)

Thanks!

ghost commented 5 years ago

Full example provided:

from multiprocessing import Process
import time
import threading
from aiohttp import web
import socketio
from asgiref.sync import async_to_sync

class SIOServer:
    def __init__(self):
        self.thread = threading.Thread(target=self._service_monitor)
        self.service_process = Process(target=self._service)
        self.service = socketio.AsyncServer()
        self.webserver = web.Application()
        self.service.attach(self.webserver)

    def start_service(self):
        print("Starting WebsocketService ...")
        self.thread.running = True
        self.thread.start()
        self.service_process.start()

    def terminate_service(self):
        print("Stopping WebsocketService ...")
        self.thread.running = False

    def _service(self):
        print("Started on localhost:29000")
        web.run_app(self.webserver, host='localhost', port=29000)

    def _service_monitor(self):
        print("Started ServiceMonitor for WebsocketService ...")
        while self.thread.running:
            time.sleep(1)
        # Kill server and terminate thread
        self.service_process.terminate()
        self.service_process.join()

if __name__ == "__main__":
    server = SIOServer()

    @server.service.on('get_bananas', namespace="/namespace1")
    async def some_request_1(sid=None, data=None):
        #server.service.enter_room(sid, f'user__{sid}')
        print(f'EMITING server_response WITH SID {sid} and namespace /namespace1')

        await server.service.emit('server_response', {}, namespace='/namespace1')
        # BUT server IS NOT DEFINED ?????

        #app.Websocket.service.leave_room(sid, f'user__{sid}')

    server.start_service()
    async_to_sync(server.service.emit)('server_response', {}, namespace='/namespace1')

    sio_client = socketio.Client()
    sio_client2 = socketio.Client()

    @sio_client.on('server_response', namespace='/api')
    @sio_client2.on('server_response')
    def handle_server_response(sid, data):
        print('SERVER RESPONDED ! YEYYY.')

    time.sleep(5)

    sio_client.connect(f'http://localhost:29000', namespaces=['/namespace1', '/chat'])
    #sio_client2.connect(f'http://localhost:29000', namespaces=['/namespace1'])

    time.sleep(3)

    async_to_sync(sio_client.emit)('get_bananas', {}, namespace='/namespace1')

    while True:
        pass

    server.terminate_service()
miguelgrinberg commented 5 years ago

The error is on this line:

async_to_sync(sio_client.emit)('get_bananas', {}, namespace='/namespace1')

This is a problem with your client, not your server. You created a sync client, and then are trying to use it as if it was an asyncio client.

ghost commented 5 years ago

I am sorry, this was adapted. The original code is like this: sio_client.emit('get_bananas', {}, namespace='/namespace1') The question is that i get the output: EMITING server_response WITH SID 20b3724e04204cf9b1dbfdfe9d8ccd7e and namespace /namespace1 --> meaning that the client 'get bananas' event was handled. But I never get the output from server_response event, handled by the client (handle_server_response) and no matter what i can never get it to be triggered

miguelgrinberg commented 5 years ago

Your server_response handlers are in different namespaces. You do not have a handler for the event and namespace that you are emitting on.

ghost commented 5 years ago

I don't know how I missed that. Thank you!