Search code examples
pythonwebsocketsocket.ioclient

Session variable value is not updated when websocket connection happens - Python


I am creating an API to send message to echo server

For this, I am using echo chat server URL ws://echo.websocket.org/ from this site https://www.websocket.org/echo.html. This connection will echo our input.

First time when the user request the API, I need to establish connection with echo server and send the user message to echo server. When second time user request the same API, this time connection is already established. So, I just need to send user message to echo server.

For this, I am using python session to store the connection details. First time when the connection in made I am trying to save it in session. session['ConnetionMade'] = "True" by default it is false

So, second time when the user request the API, this time ConnetionMade is True. So, I don't to make connection again.

But here session variable is not updated when the connection is made. It is always false. But we set to True.

Below is the full working code. Kindly help me to update session variable.

Note : Session variable works when we skips socket connection code

from flask import Flask
from flask import request, session
from config import config
import websocket

try:
    import thread
except ImportError:
    import _thread as thread


SECRET_KEY = 'a secret key'

app = Flask(__name__)
app.config.from_object(__name__)

@app.route('/')
def root():
    return 'Hello NLP....!'

userMessage = ""
@app.route('/whatsapp', methods=['POST'])
def echo():
    global userMessage
    userMessage = request.json['message']

    # session.clear()

    print("\n\nuserMessage: ", userMessage, "\n\n")

    print("ConnetionMade--: ", session.get('ConnetionMade', "False"))

    if session.get('ConnetionMade', "False") == "False":
        session['ConnetionMade'] = "True"
        print('True set to ConnetionMade ', session.get('ConnetionMade', "False"))
        echoConnection()
    else:
        session['ConnetionMade'] = "False"
        print('False set to ConnetionMade ', session.get('ConnetionMade', "False"))


    return ""


def echoConnection():

    if __name__ == "__main__":
        websocket.enableTrace(True)
        ws = websocket.WebSocketApp("ws://echo.websocket.org/",
                                  on_open = on_open,
                                  on_message = on_message,
                                  on_error = on_error,
                                  on_close = on_close)

        ws.run_forever()

    return ""

def on_message(ws, message):
    print("\n\nMessage received from Echo Socket server:", message, '\n\n')
    return

def on_error(ws, error):
    print("on_error ", error)
    return

def on_close(ws):
    print("on_close")
    return

def on_open(ws):
    def run(*args):

        print("\n\nSocket connection made. Now sending this message ("+userMessage+") to Echo Socket server\n\n")
        ws.send(userMessage)
        print("\nsent...\n")
        print("thread terminating...")

    thread.start_new_thread(run, ())

    return

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=config['server']['port'])

Solution

  • In your case, the ws.run_forever() blocks the thread and then the further call's to the API doesn't get captured.

    You can run the websocket in a deamon thread and ensure to use its send method to communicate with the websocket server.

    Something like this:

    from flask import Flask
    from flask import request, session
    import websocket
    import threading
    
    SECRET_KEY = 'a secret key'
    
    app = Flask(__name__)
    app.config.from_object(__name__)
    
    websocket_client = None
    
    @app.route('/')
    def root():
        return 'Hello NLP....!'
    
    @app.route('/whatsapp', methods=['POST'])
    def echo():
        userMessage = request.json['message']
    
        # session.clear()
        print("userMessage: ", userMessage, "\n")
        print("ConnetionMade--: ", session.get('ConnetionMade', "False"))
    
        if session.get('ConnetionMade', "False") == "False":
            session['ConnetionMade'] = "True"
            print('True set to ConnetionMade ', session.get('ConnetionMade', "False"))
            send_message_to_websocket_server(userMessage)
    
        return ""
    
    def send_message_to_websocket_server(message):
        print("Sending message to WebSocket Server")
        websocket_client.send(message)
    
    def createConnection():
        ws = websocket.WebSocketApp("ws://echo.websocket.org/",
                                  on_open = on_open,
                                  on_message = on_message,
                                  on_error = on_error,
                                  on_close = on_close)
    
        # Initialise the run_forever inside a thread and make this thread as a daemon thread
        wst = threading.Thread(target=ws.run_forever)
        wst.daemon = True
        wst.start()
        return ws
    
    def on_message(ws, message):
        print("Message received from Echo Socket server:", message)
    
    def on_error(ws, error):
        print("on_error ", error)
    
    def on_close(ws):
        print("on_close")
    
    def on_open(ws):
        print("Socket connection opened")
    
    if __name__ == "__main__":
        websocket_client = createConnection()
        app.run(host='0.0.0.0', port=8001)  # I have hardcoded the port to test this
    

    Now, using Curl if I take session into account and hit it with the following command, it only sends an echo to the websocket server if the session is new:

    curl -s -i -X POST http://0.0.0.0:8001/whatsapp\
       -d '{"message":"Sample"}' -H "Content-Type: application/json"\
       --cookie cookie.txt --cookie-jar cookie.txt
    

    It will always take the latest message and echo it to the console.