How to send an alert to client using websockets after post request in flask

Viewed 2874

How do I send a message to client after a post request is made? I store the data from the post request into a database and I want to notify the client that the database has been changed. Is there way to combine the restapi with websocket? the examples I am finding are using websockets to recieve data and send to client while I am using post method receive and want to use websocket to alert. any help would be appreciated.

server.py

import sqlite3
from flask import Flask, render_template
from flask_socketio import SocketIO

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@app.route('/', methods=['GET'])
def index():
    render_template('index.html')

# listen for data
@app.route('/listen/<data>',methods=['POST'])
def listen(data):
    # insert to db
    conn = sqlite3.connect('storage.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE info(num text)''')
    c.execute('''INSERT INTO info(num) VALUES(?)''',(data))
    conn.commit()
    conn.close()

    #send alert to client

@socketio.on('message')
def handle_message(message):
    send(message)

if __name__ == '__main__':
    socketio.run(app)

index.html

<head>
<script type="text/javascript"src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
        var socket = io.connect('http://' + document.domain + ':' + location.port);
        socket.on('message', function(data) {
             console.log(data);
        });
  </script>
</head>
2 Answers

You just got it in wrong way. Your send or emit from flask-socketio should be last statement after POST request like so:

import sqlite3
from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@app.route('/', methods=['GET'])
def index():
    render_template('index.html')

# listen for data
@app.route('/listen/<data>',methods=['POST'])
def listen(data):
    # insert to db
    conn = sqlite3.connect('storage.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE info(num text)''')
    c.execute('''INSERT INTO info(num) VALUES(?)''',(data))
    conn.commit()
    conn.close()

    emit('message', 'Change has been made', broadcast=True) # To send all who listen

# This part is, if client sends to server something through 'message' socket. You don't need that,
# @socketio.on('message')
# def handle_message(message):
    # send(message)

if __name__ == '__main__':
    socketio.run(app)

Because client listens for messages from 'message' socket, you need to handle that in your index.html like so:

<head>
<script type="text/javascript"src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
        var socket = io.connect('http://' + document.domain + ':' + location.port);
        socket.on('message', function(data) {
             console.log(data);
        });
  </script>
</head>

There is client side and server side. They both listen for some changes with socket.on() . And they send messages or emit messages with, send() and emit().

Client can emit through 'ImHere' socket -> server will handle that mesage with socket.on('ImHere') -> server can than fire up some other socket, with emit or send, lets say 'message' socket -> client can handle it on their side with `socket.on('message', function(data){...}).

You have everything is place as mentioned by @Dinko you just need to add one more in your listen function after conn.close(), which is:

socketio.emit('message', {'data': 'Records Affected'}, broadcast=True)

Your call back function will be triggered as it will hear the 'message' socket.

Just one more thing to add here is that, if you have namespace for a specific channel then you need to pass that as well

socketio.emit('message', {'data': 'Records Affected'}, broadcast=True, namespace='/test')

Hope this helps..!

Related