Python Flask Set Text in Website without reloading - python

I've created a simple flask application.
I won't show it here because there is much Bootstrap stuff in it.
My website shood look so:
Installation will be done...
> Installing Flask-Nav
After the first extension is installed:
Installation will be done...
> Configuring Flask for Extensions
And so on...
But there is also bootstrap stuff on the website. So it takes some second to load the page. But i only want to set the status label. How can i do that without refreshing the whole Page?
def install():
download("flask-nav")
config("flask-nav")
setstatus("> Downloading next extensions") #How to do that???
download("flask-appconfig")
....

Here is a very simple implementation of Flask-SocketIO. You can follow this article for better understanding
test.py
import time
from threading import Thread
from flask import Flask, render_template
from flask.ext.socketio import SocketIO, emit
app = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
thread = None
def background_thread():
"""Here is where you'll perform your installation"""
count = 0
# Call Install function 1 using time.sleep(10) to simulate installation
time.sleep(10)
count += 1
socketio.emit('my response',
{'data': '1 installed', 'count': count},
namespace='/test')
# Call Install function 2 using time.sleep(10) to simulate installation
time.sleep(10)
count += 1
socketio.emit('my response',
{'data': '2 installed', 'count': count},
namespace='/test')
# Call Install function 3 using time.sleep(10) to simulate installation
time.sleep(10)
count += 1
socketio.emit('my response',
{'data': '3 installed', 'count': count},
namespace='/test')
#app.route('/')
def index():
thread = Thread(target=background_thread)
thread.start()
return render_template('index.html')
#socketio.on('disconnect', namespace='/test')
def test_disconnect():
print('Client disconnected')
if __name__ == '__main__':
socketio.run(app)
templates/index.html
<!DOCTYPE HTML>
<html>
<head>
<title>Flask-SocketIO Test</title>
</head>
<body>
<h1>Flask-SocketIO Test</h1>
<div id="log1"></div>
<div id="log2"></div>
<script type="text/javascript" src="//code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
namespace = '/test';
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
$('#log1').html('<br>Installing Software');
$('#log2').html('<br> > ...');
socket.on('my response', function(msg) {
$('#log2').html('<br> > Received #' + msg.count + ': ' + msg.data);
});
});
</script>
</body>
</html>
Notice, the background_thread() function. That is the function where you'll call your installation functions and emit a response whenever an installation completes.

Related

Python flask realtime in render html

How can i see data from realtime on my page? When I use these codes outside of flask, the listener waits for the data to come and prints it to the screen.
My python code:
import itertools
import time
from flask import Flask, Response, redirect, request, url_for
from TikTokLive import TikTokLiveClient
from TikTokLive.types.events import CommentEvent, ConnectEvent, GiftEvent
# Instantiate the client with the user's username
client: TikTokLiveClient = TikTokLiveClient(unique_id="#username")
app = Flask(__name__)
#client.on("connect")
async def on_connect(_: ConnectEvent):
print("Connected to Room ID:", client.room_id)
#client.on("gift")
async def on_gift(event: GiftEvent):
# If it's type 1 and the streak is over
if event.gift.gift_type == 1:
f"{event.user.uniqueId} sent {event.gift.repeat_count}x \"{event.gift.extended_gift.name}\" {event.gift.extended_gift.name}"
#app.route('/')
def index():
if request.headers.get('accept') == 'text/event-stream':
return Response(on_gift(GiftEvent), content_type='text/event-stream')
return redirect(url_for('static', filename='index.html'))
if __name__ == "__main__":
app.run(debug=True)
client.run()
My index.html page
<!doctype html>
<title>Server Send Events Demo</title>
<style>
#data {
text-align: center;
}
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
if (!!window.EventSource) {
var source = new EventSource('/');
source.onmessage = function(e) {
$("#data").text(e.data);
}
}
</script>
<div id="data">nothing received yet</div>
My error

How can I send data though socket-io without the client requesting first with python and flask

My goal is for my Flask server to send the client data either every three seconds, or when a function is called. To do this I am using SocketIO. However based on some example code I am working with, it seems that I can only send data after a client requests something. I don't want the client to have to 'poll' to find if there is new data, so I want the server to push it when it is ready.
Here is what I tried so far. (some of the code is unnecessary since it is based off an example) This should use socketio to push the time to the client every few seconds.
HTML
<!DOCTYPE HTML>
<html>
<head>
<title>Socket-Test</title>
<script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
namespace = '/test';
var socket = io(namespace);
socket.on('my_response', function(msg, cb) {
$('#log').text( $('<div/>').text(msg.data).html());
if (cb)
cb();
});
});
</script>
</head>
<body style="background-color:white;">
<h1 style="background-color:white;">Socket</h1>
<div id="time" ></div>
</body>
</html>
Python
import threading
from flask import Flask, render_template, session, copy_current_request_context,request
from flask_socketio import SocketIO, emit, disconnect
from threading import Lock
import time
async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socket_ = SocketIO(app, async_mode=async_mode)
thread = None
thread_lock = Lock()
clients = []
def update():
time.sleep(1)
emit('my_response',
{'data': time.time},
room=clients[0])
t=threading.Thread(target=update)
#socket_.on('connect')
def handle_connect():
print('Client connected')
clients.append(request.sid)
t.start()
#app.route('/')
def index():
return render_template('index.html', async_mode=socket_.async_mode)
#socket_.on('my_event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': message['data'], 'count': session['receive_count']})
#socket_.on('my_broadcast_event', namespace='/test')
def test_broadcast_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': time.time},
broadcast=True)
socket_.run(app,port=8050)
I try to run it but it gives me the error RuntimeError: Working outside of request context.
I fixed my code by following this tutorial: https://www.shanelynn.ie/asynchronous-updates-to-a-webpage-with-flask-and-socket-io/
import threading
from flask import Flask, render_template, session, copy_current_request_context,request
from flask_socketio import SocketIO, emit, disconnect
from threading import Lock
import time
async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socket_ = SocketIO(app, async_mode=async_mode)
thread = None
thread_lock = Lock()
def update():
time.sleep(1)
socket_.emit('my_response',
{'data': time.time()},
namespace='/test')
print("emitted")
update()
t=threading.Thread(target=update)
#socket_.on('connect', namespace='/test')
def handle_connect():
print('Client connected')
if not t.isAlive():
t.start()
#app.route('/')
def index():
return render_template('index.html', async_mode=socket_.async_mode)
socket_.run(app,port=8070)
HTML
<!DOCTYPE HTML>
<html>
<head>
<title>Socket-Test</title>
<script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
namespace = '/test';
var socket = io(namespace);
console.log(("test"));
socket.on('my_response', function(msg) {
$('#time').text( $('<div/>').text(msg.data).html());
console.log(msg);
});
});
</script>
</head>
<body style="background-color:white;">
<h1 style="background-color:white;">Socket</h1>
<div id="time" ></div>
</body>
</html>
I would like to point out that using recursion in this case is not the best choice.
you call the update function inside the update and do not have the completion of this process.
the best option would be to use a loop(as done in the link you attached)
def update():
while True:
time.sleep(1)
socket_.emit('my_response', {'data': time.time()}, namespace='/test')
print("emitted")
t=threading.Thread(target=update)
also, it would be better to write "while is_work_var" instead of "while True"

Why are requests with same url processed synchronously?

I thought it was a quirk of the framework I was using, so I tested with another framework, but the result is the same: sending a burst of requests will process them asynchronously as expected when the urls are different, but will queue the requests with the same url and process them synchronously.
Why are some requests processed synchronously and some asynchronously?
Below the code to test with both Flask and CherryPy. Visiting localhost:5000 with Flask and localhost:8080 with CherryPy will load a page with JavaScript that will send a burst of 16 requests. The requests have an unused parameter in the query string which can have 4 different values, so the server will receive 4 different requests, each 4 times, for a total of 16 requests.
The server starts processing the first 4 requests for each parameter value, after finishing them will start processing the next 4 requests, etc.
Why aren't all 16 requests processed at the same time?
Flask
import flask
import time
import threading
import datetime
app = flask.Flask(__name__)
def log(txt):
print(' {} {:6d} {}'.format(datetime.datetime.now().strftime('%H:%M:%S.%f'),
threading.current_thread().ident,
txt))
#app.route('/')
def index():
log('index')
return """<!DOCTYPE HTML>
<html>
<head>
<script>
setTimeout(function(){{
for(i=0; i<16; i++) {{
xhttp = new XMLHttpRequest();
xhttp.open("GET", "test/" + i%4, true);
xhttp.send();
}}
}}, 2000);
</script>
</head>
<body>
hello
</body>
</html>"""
#app.route('/test/<x>')
def test(x):
log('test{}'.format(x))
time.sleep(3)
log(' test{}'.format(x))
return 'OK'
app.run(threaded=True)
CherryPy
import cherrypy
import time
import datetime
import threading
def log(txt):
print(' {} {:6d} {}'.format(datetime.datetime.now().strftime('%H:%M:%S.%f'),
threading.current_thread().ident,
txt))
class Root:
#cherrypy.expose
def index(self):
log('index')
return """<!DOCTYPE HTML>
<html>
<head>
<script>
setTimeout(function(){{
for(i=0; i<16; i++) {{
xhttp = new XMLHttpRequest();
xhttp.open("GET", "test?x=" + i%4, true);
xhttp.send();
}}
}}, 2000);
</script>
</head>
<body>
hello
</body>
</html>"""
#cherrypy.expose
def test(self, x):
log('test{}'.format(x))
time.sleep(3)
log(' test{}'.format(x))
return 'OK'
if __name__ == '__main__':
cherrypy.quickstart(Root())

Flask and Flask-SocketIO [duplicate]

This question already has an answer here:
Flask: A RESTful API and SocketIO Server
(1 answer)
Closed 7 years ago.
This seems like a very simple problem but it's got me confused nonetheless, I have a Flask application that serves up a webpage and communicates with that page via Socket.io. The Flask application looks like this:
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on_error()
def error_handler(e):
print e
#this fires
#socketio.on("connect")
def connect():
print "connected"
#this does not
#socketio.on('test')
def test_handler(message):
print "TEST WORKS"
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0')
socketio.run(app)
My page itself is very simple:
<!doctype html>
<html>
<head>
<title>Flask Socket.IO test</title>
<style>
body { font: 13px Helvetica, Arial; }
</style>
<script src="socket.io-1.4.3.js"></script>
<script src="jquery-2.2.0.min.js"></script>
<script>
var socket = io("192.168.42.1:5000");
socket.on('connect', function() {
console.log(" connected ");
});
$(document).ready( function() {
$( '.startBtn' ).click(function() {
console.log("ok");
socket.emit('test', {data:"start!"});
});
});
</script>
</head>
<body>
<div class="startBtn">
<h1>START</h1>
</div>
</body>
</html>
I see on both sides that they connect (i.e. the connect event is triggered on both sides) but nothing that I send from the page to the server is received. I'm guessing somehow I have things misconfigured but the connection being established makes me think otherwise.
So the problem seems to be in how I was setting up the Flask application and socketio. Changing it to this:
app = Flask(__name__)
socketio = SocketIO(app, async_mode='eventlet')
#app.route('/')
def index():
return render_template('index.html')
#socketio.on('test')
def josh_test(message):
print "test"
if __name__ == '__main__':
socketio.run(app, debug=True)
it now all works fantastically with no changes to the HTML file. My previous version had:
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0')
socketio.run(app)
and that was what was causing the problems.

How to escape HTML characters in Flask-SocketIO?

Based on the example on GitHub, this is my Python script:
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode='eventlet')
#app.route('/')
def index():
return render_template('index.html')
#socketio.on('my event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my response',
{'data': message['data'], 'count': session['receive_count']})
if __name__ == '__main__':
socketio.run(app, debug=True)
This is the HTML template:
<!DOCTYPE HTML>
<html>
<head>
<script src="//code.jquery.com/jquery-1.4.2.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
<script charset="utf-8">
$(document).ready(function(){
namespace = '/test'; // change to an empty string to use the global namespace
// the socket.io documentation recommends sending an explicit package upon connection
// this is specially important when using the global namespace
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
// event handler for server sent data
// the data is displayed in the "Received" section of the page
socket.on('my response', function(msg) {
$('#log').append('<br>Received #' + msg.count + ': ' + msg.data);
});
// handlers for the different forms in the page
// these send data to the server in a variety of ways
$('form#emit').submit(function(event) {
socket.emit('my event', {data: $('#emit_data').val()});
return false;
});
});
</script>
</head>
<body>
<form id="emit" method="POST" action='#'>
<input type="text" name="emit_data" id="emit_data" placeholder="Message">
<input type="submit" value="Echo">
</form>
<h2>Receive:</h2>
<div id="log"></div>
</body>
</html>
Everything works fine. But the problem is user can use any HTML tags in the messages.
For example:
I think it's little dangerous. Because any users can also run some JavaScript code and broadcast it. Then every clients will run it.
Is there's anyway can use Jinja auto escape the output, or there's any other ways?
Flask-SocketIO author here.
The example application was meant as a quick example of how to send and receive messages, I did not consider it to be an example of how to deal with user input safely.
But the point is well taken, I have updated the example app to properly handle user input now. How you do this is dependent on the application. For this example, I've chosen to do the escaping on the client side using jQuery:
$('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());
However, the way I found is, we can escape the HTML characters in the script like:
import jinja2
# other code here
#socketio.on('my event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my response',
{'data': jinja2.escape(message['data']), 'count': session['receive_count']})
# ^^^^^^^^^^^^^^ use jinja2 escape the output before send it to the clients.
Demo output:

Categories

Resources