I have a flask app which triggers some other python project function. This function creates a log output, which I'd like to display in a modal present on my flask html page, dynamically, without rendering the page again. I heard websockets are a good way to do this. I have some problems with the execution tho:
I am not sure if the structure of my project is correct - Im having problems importing the socketio app object from app.py to other modules.
PROJECTX ├── static │ ├── assets │ ├── css │ ├── js ├── templates --> Here I define my html page, with a modal that contains the websocket output ├── algorithms.py --> here I want to trigger an event: whenever I get some output from PROJECTY, I want to emit this output to a modal body ├── auth.py ├── config.py |── db.py ├── errors.py ├── app.py --> here I create a socketio app object using socketio = SocketIO(app) ├── .gitignore ├── requirements.txt └── README.md
PROJECTY ├── main.py --> my html page has a button which triggers this script; I want to emit the output of this file ├── requirements.txt └── README.md
MY ALGORITHMS.PY FILE:
from flask import Blueprint, render_template, session, request, flash, current_app as
app
from auth import token_required
from threading import Lock
from flask_socketio import emit
from flask import current_app
import json
from . import socketio
algorithms = Blueprint("algorithms", __name__)
message = []
thread = None
thread_lock = Lock()
@algorithms.route("/age-gender.html", methods=['GET', 'POST'])
@algorithms.route("/age-gender", methods=['GET', 'POST'])
@token_required
def age_gender_route(current_user):
if request.method == "POST":
global message
message = ["Damn, nice"]
"""proc = subprocess.Popen(
['pwd'], #call something with a lot of output so we can see it
shell=True,
stdout=subprocess.PIPE
)
for line in iter(proc.stdout.readline,''):
if line != b'':
message.append(line)"""
return message
elif request.method == "GET":
return render_template("algorithms/age-gender.html",
logged_user=session.get("username"))
def background_thread(app):
with app.app_context():
while True:
socketio.sleep(5)
if message:
socketio.emit('new_alerts', {'msg': 'New alert', 'id': message[0]}, namespace='/rt/notifications/')
@socketio.event
def my_event(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': message['data'], 'count': session['receive_count']})
@socketio.event
def connect():
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(background_thread, current_app._get_current_object())
emit('my_response', {'data': 'Connected', 'count': 0})
MY HTML FILE:
{% block scripts %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js" integrity="sha512-aMGMvNYu8Ue4G+fHa359jcPb1u+ytAF+P2SCb+PxrjCdO3n3ZTxJ30zuH39rimUggmTwmh2u7wvQsDTHESnmfQ==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
// Connect to the Socket.IO server.
// The connection URL has the following format, relative to the current page:
// http[s]://<domain>:<port>[/<namespace>]
var socket = io();
// Event handler for new connections.
// The callback function is invoked when a connection with the
// server is established.
socket.on('connect', function() {
socket.emit('my_event', {data: 'I\'m connected!'});
});
// Event handler for server sent data.
// The callback function is invoked whenever the server emits data
// to the client. The data is then displayed in the "Received"
// section of the page.
socket.on('my_response', function(msg, cb) {
$('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());
if (cb)
cb();
});
});
</script>
AND MY APP.PY
import subprocess
from flask import Flask, render_template, request, session, redirect, url_for
from config import *
from auth import auth as auth_blueprint, token_required
from errors import errors as errors_blueprint
from algorithms import algorithms as algorithms_blueprint
from flask_socketio import SocketIO
app = Flask(__name__, template_folder="templates", static_folder="static")
app.register_blueprint(algorithms_blueprint)
app.config.from_object(Development_Config)
socketio = SocketIO(app)
...
if __name__ == "__main__":
socketio.run(app)
PROBLEMS I HAVE: Importing the socketio from app.py to algorithms.py Starting to emit info only when the modal is opened Getting the output from the other project --> maybe there is a better way than getting the output using subprocess? In this way, I have to wait for the whole output to be completed, and it will be emited all at once, instead of being emited dynamically.
Any help is more than welcome!!!