Reputation: 11
I asked a similar question previously here: flask-socketio --> Client not receiving emits from server Instead of adding a comment to previous post I thought it would be better to post a new question for help...
I want to use flask-socketio in my app (builded according to the factory application principle) which uses blueprints. The connection is working (the 'connect' socket gets triggered). But as with the previous post, when I manually trigger a def() which uses emit(), nothing is received on client side.
The simplified code:
__init__.py
from flask import Flask
from flask_socketio import SocketIO
gv_socketio = SocketIO(logger=True, engineio_logger=True)
def create_app():
#instance_relative_config=True --> instance folder is located outside of
#main (in this case 'spotr') folder.
app = Flask(__name__, instance_relative_config=True)
#default configuration settings. 'spotr.sqlite' will be located in instance #folder.
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'spotr.sqlite'),
)
#overrides default configuration with values written in 'config.py'.
app.config.from_pyfile('config.py', silent=True)
#socketio extension
gv_socketio.init_app(app)
#instance folder exists?
try:
os.makedirs(app.instance_path)
except OSError:
pass
with app.app_context():
#register blueprint(s)
from . import watchlist, home, database #blueprints
app.register_blueprint(watchlist.bp_watchlist)
app.register_blueprint(home.bp_home)
app.register_blueprint(database.bp_database)
return app
watchlist.py:
from flask_socketio import emit
from . import gv_socketio
bp_watchlist = Blueprint('watchlist', __name__, url_prefix="/watchlist")
def sendStatusViaSocket(note):
gv_socketio.emit('updateStatus', {"data": note}, namespace='/watchlist')
@bp_watchlist.route("/", methods=["GET","POST"])
def watchlist_main():
args=request.args
#--> PAGE LOAD #
if request.method == "GET" and not ("addArtist" in args):
sendStatusViaSocket("11111111111111")
return render_template('watchlist.html')
watchlist.html:
{% extends 'base.html' %}
{% block title %}
Watchlist
{% endblock %}
{% block content %}
<!-- socketio interface -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.1/socket.io.js"></script>
<script>
socket = io();
socket.connect('http://' + document.domain + ':' + location.port + '/watchlist');
socket.on('updateStatus',function(data){
console.log('HEY');
//console.log(data.data);
})
socket.on('connect',function(){
console.log('CONNECT');
})
socket.on('message',function(msg){
console.log("MESSAGE");
})
</script>
<!-- -->
....
{% endblock %}
So I would expect that when I trigger def watchlist_main(), sendStatusViaSocket() gets triggered in turn and emits to the client (watchlist.html) so that on client side, 'updateStatus' gets triggered. But nothing gets triggered on client side. Only thing that happens is that 'connect' appears in the client's console log. In the browser's debugger I see that 'updateStatus' nor 'message' gets triggered in someway.
What am I doing wrong this time?
I've found similar threads where the 'Flask-SocketIO-Chat' repository is used as example. I've used that repo as a guideline but I don't see what I'm missing.
The socket logger shows the following after loading watchlist.html:
127.0.0.1 - - [21/Aug/2022 13:29:35] "GET /watchlist/ HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2022 13:29:35] "GET /static/style.css HTTP/1.1" 304 -
**The WebSocket transport is not available, you must install a WebSocket server that is compatible with your async mode to enable it. See the documentation for details. (further occurrences of this error will be logged with level INFO)**
bYHyaOm5DEHy1S5XAAAA: Sending packet OPEN data {'sid': 'bYHyaOm5DEHy1S5XAAAA', 'upgrades': [], 'pingTimeout': 20000, 'pingInterval': 25000}
127.0.0.1 - - [21/Aug/2022 13:29:35] "GET /socket.io/?EIO=4&transport=polling&t=OB0AbE6 HTTP/1.1" 200 -
bYHyaOm5DEHy1S5XAAAA: Received packet MESSAGE data 0
CONNNNECT
bYHyaOm5DEHy1S5XAAAA: Sending packet MESSAGE data 0{"sid":"Q941dFU3MYnD-ydkAAAB"}
127.0.0.1 - - [21/Aug/2022 13:29:35] "GET /socket.io/?EIO=4&transport=polling&t=OB0AbHH&sid=bYHyaOm5DEHy1S5XAAAA HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2022 13:29:35] "POST /socket.io/?EIO=4&transport=polling&t=OB0AbHG&sid=bYHyaOm5DEHy1S5XAAAA HTTP/1.1" 200 -
bYHyaOm5DEHy1S5XAAAA: Received packet MESSAGE data 2["done"]
received event "done" from Q941dFU3MYnD-ydkAAAB [/]
127.0.0.1 - - [21/Aug/2022 13:29:35] "POST /socket.io/?EIO=4&transport=polling&t=OB0AbI0&sid=bYHyaOm5DEHy1S5XAAAA HTTP/1.1" 200 -
Maybe the 'websocket server' warning means something? Digging into this hasn't brought me much yet. I tried installing gevent-websocket and eventlet but no success yet.
Thank you!
Upvotes: 0
Views: 1116
Reputation: 942
Generally, things can go wrong when using circular imports. An alternative approach is passing the socket object to the blueprint through the app (defining the socket as an app attribute). Here is what I would recommend trying:
__init__.py
from flask import Flask
from flask_socketio import SocketIO
gv_socketio = SocketIO(logger=True, engineio_logger=True)
def create_app():
#instance_relative_config=True --> instance folder is located outside of
#main (in this case 'spotr') folder.
app = Flask(__name__, instance_relative_config=True)
#default configuration settings. 'spotr.sqlite' will be located in instance #folder.
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'spotr.sqlite'),
)
#overrides default configuration with values written in 'config.py'.
app.config.from_pyfile('config.py', silent=True)
#socketio extension
gv_socketio.init_app(app)
#instance folder exists?
try:
os.makedirs(app.instance_path)
except OSError:
pass
with app.app_context():
app.gv_socketio = gv_socketio
#register blueprint(s)
from . import watchlist, home, database #blueprints
app.register_blueprint(watchlist.bp_watchlist)
app.register_blueprint(home.bp_home)
app.register_blueprint(database.bp_database)
return app
watchlist.py
from flask import current_app
from flask_socketio import emit
bp_watchlist = Blueprint('watchlist', __name__, url_prefix="/watchlist")
@bp_watchlist.route("/", methods=["GET","POST"])
def watchlist_main():
args=request.args
#--> PAGE LOAD #
if request.method == "GET" and not ("addArtist" in args):
current_app.gv_socketio.emit('updateStatus', {"data": "11111111111111"}, namespace='/watchlist')
return render_template('watchlist.html')
Upvotes: 0