I've some problem in sending a simple message trough socket.io:
giving a button in index.html:
<button id="button" onclick="functionTest()"> buttonTest </button>
and this function in my js :
function functionTest( function(event) {
socket.emit('myevent', {data: "testval"});
return false;
});
if I have a Flask server with:
#socketio.on('myevent', namespace='/test')
def test_message(message):
print message
I should see in the Flask log, the message, but it doesn't work.
Where am I wrong?
thank you
Related
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")
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
Task
Perform a POST request from a JS method, so that variable values can be sent as parameters.
Environment
NodeJS
Express
BodyParser
ejs
My first attempt
Frontend:
<html>
<head>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js'></script>
<script type="text/javascript">
function postAnswer() {
$.post('vote', { message: "hello!"}, function(returnedData) {
console.log("Post returned data: " + returnedData);
});
}
</script>
</head>
<body>
<button id='send' onClick='postAnswer()' class='btn btn-success btn-xs'>Svara</button>
</body>
</html>
Server.js:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser());
require('./app/routes.js')(app);
app.set('view engine', 'ejs');
app.use('/public', express.static(__dirname + '/public'));
var server = require('http').createServer(app);
server.listen(8080);
console.log('Server running on port 8080...');
routes.js:
module.exports = function(app) {
app.get('/', function(req, res) {
res.render('vote.ejs', {
message: ''
});
});
app.post('/vote', function(req, res) {
var msg = req.body.message;
console.log("Got POST request with message: " + msg);
res.render('index.ejs', {
message: ''
});
});
};
Result:
The render method won't render a new page. It will however return the entire 'index.ejs' file in the returnedData parameter.
Server:
Client:
Second attempt:
<html>
<head>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js'></script>
<script type="text/javascript">
function postAnswer() {
$.post('vote', { message: "hello!"}, function(returnedData) {
console.log("Post returned data: " + returnedData);
});
return false;
}
</script>
</head>
<body>
<form action='/vote' method='post'>
<button id='send' type='submit' onsubmit='return postAnswer()' class='btn btn-success btn-xs'>Svara</button>
</form>
</body>
</html>
Result:
This does work, but it's not a very clean solution.
My questions:
Why doesn't the first attempt work?
How can I send variables as parameters to a POST request with a nice clean solution?
I'm not a jQuery expert, but I think the first attempt doesn't work because $.post makes an AJAX request, the same way as you would in a single-page app to interact with an API in the background.
Your second example submits a form, which is an in-browser action that performs a navigation action (as specified by the method attribute of the form). In this case, the event listener you add in jQuery is redundant, and should be removed - it's making another background POST request, before the form submits the content of its fields in its request.
As for your second question, the way to submit additional variables with a form submission (presuming that you actually want to do a navigating form submission and not an XHR background request against an API) is to use <input type="hidden"> elements.
So, to summarize, to do what you're describing in your question, your example HTML should look like this (minus the comments):
<!DOCTYPE html> <!-- only you can prevent quirks mode -->
<html>
<head>
<meta charset="UTF-8"> <!-- ༼ つ ◕_◕ ༽つ Give UNICODE -->
</head>
<body>
<form action='/vote' method='post'>
<input type="hidden" name="message" value="hello!">
<button id='send' type='submit' class='btn btn-success btn-xs'>Svara</button>
</form>
</body>
</html>
I have the following code below :
<!DOCTYPE html>
<html>
<head>
<script src="http://connect.soundcloud.com/sdk.js"></script>
<script>
SC.initialize({
client_id: "f520d2d8f80c87079a0dc7d90db9afa9"
});
SC.get("/users/3207",{}, function(user){
console.log("in the function w/ " + user);
});
</script>
</head>
</html>
The code should print the user name to the console however whenever I run this, my console gives the error of :
Failed to load resource: The requested URL was not found on this server:
file://api.soundcloud.com/users/3207?client_id=f520d2d8f80c87079a0dc7d90db9afa9&format=json&_status_code_map%5B302%5D=200
However if I were to directly http://api.soundcloud.com/users/3207.json?client_id=f520d2d8f80c87079a0dc7d90db9afa9, then I get a valid JSON result.
Is there something incorrect with my how I am using the SC.get function?
Thanks
Well, you should test your index.html locally on a web-server like Apache and not by opening it as a file.
Working example
SC.initialize({
client_id: "f520d2d8f80c87079a0dc7d90db9afa9"
});
SC.get("/users/3207", {}, function(user) {
console.log("in the function w/ " + JSON.stringify(user));
var res = document.getElementById("result");
res.innerHTML = JSON.stringify(user);
});
<script src="http://connect.soundcloud.com/sdk.js"></script>
<div id="result"></div>
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.