Flask SocketIO messages not received - javascript

I am new to Flask and the IO. I'm trying to implement a basic data receiver for a machine with RoS. I have a python script sending data to a web server running on Flask.
The issue is that the java-script callback is never called and thus the numbers are strangely never added to the list, even though there are no errors.
The relevant parts are this:
Within Python Webserver:
#socketio.on('connect', namespace='/test')
def test_connect():
print("CALLED")
#socketio.on('disconnect', namespace='/test')
def test_disconnect():
print('Client disconnected')
It is supposed to post a random number defined by the following Ros Callback function (This is called every 0.5s):
def forklift_callback(self, msg):
#SOCKET TEST
number = random.randint(1,101)
print(number)
socketio.emit('newnumber', {'number': number}, namespace='/test')
Perhaps the way I define it is important:
*import statements*
from std_msgs.msg import String, UInt32
from umd_msgs.msg import PCNotification, RoverStatus, Barcode
mod = Blueprint('api', __name__)
msg = String()
started = "robot started"
socketio = SocketIO(app)
... All functionality ...
if __name__ == '__main__':
socketio.run(app)
This is connected to the html page at the following location:
<html>
<head>
<script src="//code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script>
$(document).ready(function(){
//connect to the socket server.
console.log('http://' + document.domain + ':' + location.port + '/test')
var socket = io.connect('http://' + document.domain + ':' + location.port + '/test');
var numbers_received = [];
//receive details from server
socket.on('newnumber', function(msg) {
console.log("Blank")
console.log("Received number" + msg.number);
//maintain a list of ten numbers
if (numbers_received.length >= 10){
numbers_received.shift()
}
numbers_received.push(msg.number);
numbers_string = '';
for (var i = 0; i < numbers_received.length; i++){
numbers_string = numbers_string + '<p>' + numbers_received[i].toString() + '</p>';
}
$('#log').html(numbers_string);
});
});
</script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="jumbotron">
<h1>Asynchronous Flask Communication</h1>
<p>Random numbers generated by the Flask server will appear below, asynchronously.</p>
</div>
</div>
</div>
<div class="container" id="content">
<div class="row">
<p>Asynchronous page updates will appear here:</p>
<h3>Number list:</h3>
<div id="log">
</div> <!-- /#log -->
</div>
</div>

Try somethin like this,maybe it helps
You can do it with Thread that will run your function
yourThread = Thread()
thread_stop_event = Event()
class someClass(Thread):
def __init__(self):
self.delay = 1
super(someClass,self).__init__()
def forklift_callback(self):
while not thread_stop_event.isSet():
number = random.randint(1,101)
print(number)
socketio.emit('newnumber', {'number': number}, namespace='/test')
sleep(self.delay)
def run(self):
self.forklift_callback()
#socketio.on('connect', namespace='/test')
def test_connect():
print("CALLED")
global yourThread
if(not yourThread.isAlive()):
yourThread = someClass()
yourThread.start()
or just run it after client connects your server
#socketio.on('connect', namespace='/test')
def test_connect():
//your function here
print("CALLED")

Related

Flask event stream app with js eventsource overwrites previous stream output

My flask app:
import eventlet
eventlet.monkey_patch()
from flask import Flask, render_template, Response
from shelljob import proc
from time import sleep
app = Flask(__name__)
#app.route('/')
def index():
return render_template('stream.html')
#app.route('/stream')
def stream():
g = proc.Group()
p = g.run([ "bash", "-c", "sudo tcpdump -i ens4 -s 0 -nX tcp port 5000" ])
def read_process():
while g.is_pending():
lines = g.readlines()
for proc, line in lines:
yield "data:" + str(line) + "\n\n"
return Response(read_process(), mimetype='text/event-stream')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5001)
stream.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Output</h1>
<div id="dumps"></div>
</body>
<script>
var targetContainer = document.getElementById("dumps");
var eventSource = new EventSource("/stream");
eventSource.onmessage = function(e) {
targetContainer.innerHTML = e.data;
};
</script>
</html>
My issue:
The outputs seems to get to the browser but any new streamed output overwrites the previous one. For e.g. the following is all i see in the browser and the line keeps changing as stream is updated:
Output
b'\t0x0020: 8011 01fa ce65 0000 0101 080a 1984 6ce7 .....e........l.\n' <=== keeps updating
What i'd like to achieve is a stream of tcpdump output rendered on my browser as an actual bash output would look like.
This works fine if i point to url path /stream and the reason why i'm embedding into html is to be able to give it some style.
Changed to targetContainer.innerHTML += e.data + "<br/> in <script>

Passing a variable from the backend to the frontend in a Flask app

Basically I want the code below to put the "search" from the backend to the frontend.
I am having trouble getting my flask app to pass data from the back end to the front end using templates and a simple flask structure.
I am open to suggestions for better ways. Also # Daniel Mesejo has been a great help so far in my learning about Flask and ajax/jquery.
here is my app.py
from scraper import scrape
from flask import Flask, render_template, jsonify, make_response, request
import json
app = Flask(__name__)
#app.route("/", methods=['GET', 'POST'])
def index():
entries = json.dumps(scrape("video games"))
return render_template('index.html', entries= entries)
#app.route('/parse_data', methods=['GET', 'POST'])
def parse_data():
if request.method == "POST":
#data = request.form("blah")
#print("blah")
search = request.get_json()
#new_search = json.dumps(scrape(data))
return jsonify(search)
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=5000)
here is my index.html
<!DOCTYPE html>
<html>
<head>
<title>Flask app</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<div class="topnav">
<a class="active" href="#home">Home</a>
About
Contact
<form class = "form" action="" method="POST">
<input id ="textbox" name="textbox" type="text" placeholder="Search..">
<button type="submit">submit</button>
</form>
</div>
<p>you searched: {{search}} </p>
<div id="div1">
<p id="p1"></p>
<p id="p2"></p>
</div>
<script>
var value = $('.textbox').val();
//alert(value);
$("button").click(function (e) {
e.preventDefault();
var value = $("#textbox").val();
alert(value);
$.ajax({
type: 'POST',
url: "parse_data",
data: JSON.stringify({"text" : value}),
contentType: 'application/json; charset=utf-8',
success: function(data){
alert(JSON.stringify(data));
}
});
});
var jsonz = {{ entries|tojson }};
var s = JSON.parse(jsonz);
var i;
for (i = 0; i < s.length; i++) {
var para = document.createElement("p");
var node = document.createTextNode(s[i].product_name + "\n" + s[i].product_link);
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
}
//document.getElementById("user").innerHTML =
//obj;
//"Name: " + obj.product_name + "<br>" +
//"Location: " + obj.product_link;
</script>
</body>
</html>
To achieve want that simply change the function you pass to success like this:
success: function (data) {
$("#search-query").text("you search: " + data["text"]);
}
and change the <p> element to <p id="search-query"> you searched: </p>.
To learn more about Flask and web development in general I suggest the Flask Mega Tutorial, in here.

Javascript client will not continuously listen with Flask-SocketIO

I am learning websockets with Flask-SocketIO. The goal is to get have my div continuously populated by a random number every second. When I run the code below, only the last number appears. However in the console I see that all arrive at the same time.
<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/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
socket.on('pony_update', function(msg){
console.log("pony update");
console.log(msg);
$('#ponies').html(msg.data);
});
To update this div
<div id="ponies"></div>
The "controller" method is
#socketio.on('the_ponies', namespace='/test')
def run_numbers(message):
for i in range(5):
time.sleep(1)
x = random.random()
emit('pony_update', {'data': x}, broadcast=True)
It blocks in the thread. Try use start_background_task with gevent monkey_patch
#socketio.on('pony_update', namespace='/chat')
def run_numbers(message):
#copy_current_request_context
def back_work():
print('start')
for i in range(5):
time.sleep(1)
x = random.random()
print(x)
emit('my response', {'data': x}, broadcast=True)
socketio.start_background_task(target=back_work)
Please don't forgot to put the monkey patch in top of your file. :)

Why is my WebSocket automatically closing using Flask?

I've set up a very basic websocket server using flask.
websocket.py
from flask import Flask
from flask_uwsgi_websocket import GeventWebSocket
app = Flask(__name__)
ws = GeventWebSocket(app)
#app.route('/')
def index():
return render_template('index.html')
#ws.route('/foobar')
def echo(wscon):
msg = wscon.receive()
if msg is not None:
wscon.send(msg)
if __name__ == '__main__':
app.run(gevent=1000, host='0.0.0.0', port=9090)
index.html
<html>
<head>
<script language="Javascript">
var s = new WebSocket("ws://192.168.3.49:9090/foobar");
s.onopen = function() {
alert("connected !!!");
s.send("js send to server");
};
s.onmessage = function(e) {
alert("recv message")
var bb = document.getElementById('blackboard')
var html = bb.innerHTML;
bb.innerHTML = html + '<br/>' + e.data;
};
s.onerror = function(e) {
alert('error');
alert(e);
}
s.onclose = function(e) {
alert("connection closed");
}
function invia() {
var value = document.getElementById('testo').value;
alert(value);
s.send(value);
}
</script>
</head>
<body>
<h1>WebSocket</h1>
<input type="text" id="testo"/>
<input type="button" value="invia" onClick="invia();"/>
<div id="blackboard" style="width:640px;height:480px;background-color:black;color:white;border: solid 2px red;overflow:auto">
</div>
</body>
when I access http://ip:9090, I get the blow information:
connected !!!
recv message
connection closed
why websocket auto close? And occasionally there will be an error
[uwsgi-http key: 192.168.3.49:9090 client_addr: 192.168.3.1
client_port: 9177] hr_instance_read(): Connection reset by peer
[plugins/http/http.c line 646]
Seems like your are trying for echo gevent server. Example code
You need to keep the connection running by a loop. Change as following:
#ws.route('/foobar')
def echo(ws):
while True:
msg = ws.receive()
print(msg)
if msg is not None:
ws.send(msg)
else:
return

get multiple variables from form with websockets in python

Just starting to learn websockets and python. for now I am using Socket-IO and have the very basic 'pull from form and echo it back out' but I need to be able to pull in 2+ variables from the form and use them in the program. The guides i have seen for the beginner are all just one variable and i'm struggling to figure it out and could use some help.
Im looking for a second text field in the form and be able to get the variable in the app. I'm assuming it would be in the form of {'data': message['data']} and {'data': message['data2']} for instance but as long as I can get the values, thats whats important.
What I have right now:
index.html
<!DOCTYPE HTML>
<html>
<head>
<title>Flask-SocketIO Test</title>
<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'; // change to an empty string to use the global namespace
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
socket.on('connect', function() {
socket.emit('my event', {data: 'Connected... Waiting for you...'});
});
socket.on('my response', function(msg) {
$('#log').append('<br>' + msg.data);
});
$('form#emit').submit(function(event) {
socket.emit('my event', {data: $('#emit_data').val()});
return false;
});
});
</script>
</head>
<body>
<h1>Flask-SocketIO Test</h1>
<h2>Send:</h2>
<form id="emit" method='POST' action='#'>
<input type="text" name="emit_data" id="emit_data" placeholder="Message"><br>
<input type="submit" value="Echo"></div>
</form>
<h2>Receive:</h2>
<div id="log"></div>
</body>
</html>
app.py
from gevent import monkey
monkey.patch_all()
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():
"""Example of how to send server generated events to clients."""
count = 0
while True:
time.sleep(60)
count += 1
#'<br>Received #' + msg.count + ': ' + msg.data
socketio.emit('my response', {'data': 'Connection to server still alive'}, namespace='/test')
#app.route('/')
def index():
#kick off thread that every 10 seconds sends a response
global thread
if thread is None:
thread = Thread(target=background_thread)
thread.start()
return render_template('index.html')
#socketio.on('my event', namespace='/test')
def test_message(message):
print message
emit('my response', {'data': message['data']})
#socketio.on('connect', namespace='/test')
def test_connect():
emit('my response', {'data': 'Trying to connect to server...'})
#socketio.on('disconnect', namespace='/test')
def test_disconnect():
print('Client disconnected')
if __name__ == '__main__':
socketio.run(app)
Im looking for a second text field in the form and be able to get the variable in the app. I'm assuming it would be in the form of {'data': message['data']} and {'data': message['data2']} for instance but as long as I can get the values, thats whats important.
Just send as many variables as you want:
socket.emit('my event', {data: $('#emit_data').val(), data2: $('#emit_data2').val()});
data is only an example name for a variable. You can use any number and names of dictionary keys.

Categories

Resources