Home > other >  Using socket.io with React and python: I can't get the decorator to trigger
Using socket.io with React and python: I can't get the decorator to trigger

Time:09-02

I'm using socket.io with python 3.10 (I'm using flask but not tied to it) and React for the front end. I seem to be connected okay, and the python server is aware of the pings coming in, but the message endpoints I've written don't get triggered.

Here is my python:

import socketio
from flask import Flask, render_template

# standard Python
sio = socketio.Server(
    logger=True, engineio_logger=True, async_mode='threading', 
    # cors_allowd_origns="http://localhost:3000" # doesn't work for some reason
    cors_allowed_origins="*"
)

app = Flask(__name__)
app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app)

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=3001)


@sio.on('ping')
def ping(sid, data):
    print('did a ping!')
    print('ping', sid, data)
    exit('this should fire')

And here's my React:

const App = () => {
  const [isConnected, setIsConnected] = useState(socket.connected);
  const [lastPong, setLastPong] = useState(null);

  useEffect(() => {
    socket.on('connect', () => {
      console.log('connected')
      setIsConnected(true);
    });

    socket.on('disconnect', () => {
      console.log('disconnected')
      setIsConnected(false);
    });

    socket.on('pong', () => {
      console.log('pong')
      setLastPong(new Date().toISOString());
    });

    socket.on('message', () => {
      console.log('message')
    });

    return () => {
      socket.off('connect');
      socket.off('disconnect');
      socket.off('pong');
    };
  }, []);

  const sendPing = () => {
    const message = {
      id: 10,
      user: 'alex',
      time: Date.now(),
      data: 'test',
    };

    console.log('ping', message);
    // console.log('ping done');
    socket.emit('ping', message);
    // socket.send('hello');
  }

  // Render the Slate context.
  return (
    <div className='context-context'>
      <p>Connected: { ''   isConnected }</p>
      <p>Last pong: { lastPong || '-' }</p>
      <button onClick={ sendPing }>Send ping</button>
      <div className='editor-context'>
        <EditableInput></EditableInput> // this is defined elsewhere
      </div>
    </div>
  )
}

I am able to connect okay, and when I press 'send ping', I get this:

received event "ping" from fpyAKmiwmwkO6tpoAAAB [/]
127.0.0.1 - - [01/Sep/2022 13:28:41] "POST /socket.io/?EIO=4&transport=polling&t=OBwlTWh&sid=ei_zgp4tafpqY35xAAAA HTTP/1.1" 200 -

But the code I've written in the ping function does not get hit. What I am doing wrong?? I've wracked my brains and can't figure this one out.

CodePudding user response:

A solution that I don't fully understand seemed to work. Rather than run the script in the typical python main.py or flask run ways, I installed something called gunicorn (a unicorn with a gun?):

gunicorn -k gevent -b 127.0.0.1:3001 'main:app'

This seems to work. Any insight about why would be appreciated! I don't feel like I learned anything in this 24 hr experience.

CodePudding user response:

I don't know React so I can't run your code to test it.

I think problem can be because you define ping after app.run().

When you run flask then first it runs app.run() and it blocks rest of code and it can't execute @sio.on('ping') to assign this function to socket. And ping doesn't work.

I assumed you run it as python main.py which runs it directly.
flask run could work because it imports code.


This should work

import socketio
from flask import Flask, render_template

# standard Python
sio = socketio.Server(
    logger=True, engineio_logger=True, async_mode='threading', 
    # cors_allowd_origns="http://localhost:3000" # doesn't work for some reason
    cors_allowed_origins="*"
)

@sio.on('ping')
def ping(sid, data):
    print('did a ping!')
    print('ping', sid, data)
    exit('this should fire')

# ---

app = Flask(__name__)
app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app)

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=3001)

When you use gunicorn then it doesn't run it directly but it imports code from main.py. And import always skips code inside if __name__ == '__main__': and code can run @sio.on('ping').

And later gunicorn will use own method to start app.run()

  • Related