Search code examples
pythonflasksession-variablespython-decoratorsflask-socketio

Can't access Flask session variables as decorator arguments (in flask-SocketIO)


I am working on a multi-channel chat using custom namespaces as per flask-SocketIO, documentation. To store the channel, I use session-variables that are accessed without issues across my routes/functions, but inside @socketio.on(), the variable just does not work (it works fine if I spell the namespace-string out as @socketio.on("send", namespace = "/test"). Any ideas why???

import os
import eventlet
import json

from flask import Flask, render_template, request, jsonify, session
from flask_session import Session
from tempfile import mkdtemp
from flask_socketio import SocketIO, emit, Namespace

app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")

app.config["SESSION_FILE_DIR"] = mkdtemp()
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app) 

socketio = SocketIO(app, logger=True, engineio_logger=True)

channels = []
messagetext = None

# [OTHER FUNCTIONS SETTING session["namespace"] ]


@socketio.on("send", namespace = session["namespace"])
def handle_send(data): 
  messagetext = data["message"]
  print("THE MESSAGE IS :"+messagetext)
  emit("broadcast message", {"message": messagetext}, broadcast = True)


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


Here is the client-side JavaScript snippet, in case relevant:

function connectSocket(channel) {

  var socket = io(`/${channel}`);
  socket.on('connect', () => {
    document.querySelector('#current_channel').innerHTML = channel;
    document.querySelector('#send_message').onsubmit = () => {
      var message = document.querySelector('#message').value;
      console.log(`MESSAGE IS ${message}`);
      socket.emit('send', {'message': message}); 
      return false;
    }
  });
}

Solution

  • Decorators execute when the module is imported, unlike the actual handler functions. At that early time there is no active request being handled, so there is no client. Since there is no actual client, session does not have any meaning.

    I think you are not using namespaces in the expected way. You can't really have dynamic namespaces, you have to define a list of discrete namespaces and then implement handlers for all of them. For most applications this isn't very useful, so in most cases there is a single namespace for the entire application.

    More information on namespaces: https://socket.io/docs/rooms-and-namespaces/