Send UDP Data from Python to Javascript? - javascript

How do I retrieve data fro this Python Server in Javacript. The end goal is to be able to use Python variables to Control Javascript variables. I've scoured everywhere for hints on how to work with sockets and javascript but they only dive into sending data whereas I'm wanting to receive data.
Thanks in Advance! :)
Python Server Code:
import socket
UDP_IP = socket.gethostname()
UDP_PORT = 5005
ip_address = socket.gethostbyname(socket.gethostname())
MESSAGE = "Hello, World!"
print ("UDP target IP:", UDP_IP)
print("IP Address is",ip_address)
print ("UDP target port:", UDP_PORT)
print ("message:", MESSAGE)
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
#sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
sock.sendto(bytes(MESSAGE, "utf-8"), (ip_address, UDP_PORT))
JAVASCRIPT CLIENT:
var socket = io.connect('http://127.0.0.1:5005');

Best option should be flask
#app.route('/')
def hello():
data = {'username': 'Pang', 'site': 'stackoverflow.com'}
return render_template('settings.html', data=data)
In the above code you specify the route and the data you want to send, previously processed in a python variable.
In your js:
function myFunc(vars) {
return vars
}
In this way you should be able to view your values and use them
In your html
<html>
<head>
<script type="text/javascript" {{ url_for('static', filename='app.js')}}></script>
<script type="text/javascript">
myVar = myFunc({{vars|tojsenter code hereon}})
</script>
</head>
In the above code you store your data reciebed in MyVar, you can omit the json parsing.

Related

Flask returning a generator and handling it in JavaScript [duplicate]

I have a view that generates data and streams it in real time. I can't figure out how to send this data to a variable that I can use in my HTML template. My current solution just outputs the data to a blank page as it arrives, which works, but I want to include it in a larger page with formatting. How do I update, format, and display the data as it is streamed to the page?
import flask
import time, math
app = flask.Flask(__name__)
#app.route('/')
def index():
def inner():
# simulate a long process to watch
for i in range(500):
j = math.sqrt(i)
time.sleep(1)
# this value should be inserted into an HTML template
yield str(i) + '<br/>\n'
return flask.Response(inner(), mimetype='text/html')
app.run(debug=True)
You can stream data in a response, but you can't dynamically update a template the way you describe. The template is rendered once on the server side, then sent to the client.
One solution is to use JavaScript to read the streamed response and output the data on the client side. Use XMLHttpRequest to make a request to the endpoint that will stream the data. Then periodically read from the stream until it's done.
This introduces complexity, but allows updating the page directly and gives complete control over what the output looks like. The following example demonstrates that by displaying both the current value and the log of all values.
This example assumes a very simple message format: a single line of data, followed by a newline. This can be as complex as needed, as long as there's a way to identify each message. For example, each loop could return a JSON object which the client decodes.
from math import sqrt
from time import sleep
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
#app.route("/stream")
def stream():
def generate():
for i in range(500):
yield "{}\n".format(sqrt(i))
sleep(1)
return app.response_class(generate(), mimetype="text/plain")
<p>This is the latest output: <span id="latest"></span></p>
<p>This is all the output:</p>
<ul id="output"></ul>
<script>
var latest = document.getElementById('latest');
var output = document.getElementById('output');
var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for('stream') }}');
xhr.send();
var position = 0;
function handleNewData() {
// the response text include the entire response so far
// split the messages, then take the messages that haven't been handled yet
// position tracks how many messages have been handled
// messages end with a newline, so split will always show one extra empty message at the end
var messages = xhr.responseText.split('\n');
messages.slice(position, -1).forEach(function(value) {
latest.textContent = value; // update the latest value in place
// build and append a new item to a list to log all output
var item = document.createElement('li');
item.textContent = value;
output.appendChild(item);
});
position = messages.length - 1;
}
var timer;
timer = setInterval(function() {
// check the response for new data
handleNewData();
// stop checking once the response has ended
if (xhr.readyState == XMLHttpRequest.DONE) {
clearInterval(timer);
latest.textContent = 'Done';
}
}, 1000);
</script>
An <iframe> can be used to display streamed HTML output, but it has some downsides. The frame is a separate document, which increases resource usage. Since it's only displaying the streamed data, it might not be easy to style it like the rest of the page. It can only append data, so long output will render below the visible scroll area. It can't modify other parts of the page in response to each event.
index.html renders the page with a frame pointed at the stream endpoint. The frame has fairly small default dimensions, so you may want to to style it further. Use render_template_string, which knows to escape variables, to render the HTML for each item (or use render_template with a more complex template file). An initial line can be yielded to load CSS in the frame first.
from flask import render_template_string, stream_with_context
#app.route("/stream")
def stream():
#stream_with_context
def generate():
yield render_template_string('<link rel=stylesheet href="{{ url_for("static", filename="stream.css") }}">')
for i in range(500):
yield render_template_string("<p>{{ i }}: {{ s }}</p>\n", i=i, s=sqrt(i))
sleep(1)
return app.response_class(generate())
<p>This is all the output:</p>
<iframe src="{{ url_for("stream") }}"></iframe>
5 years late, but this actually can be done the way you were initially trying to do it, javascript is totally unnecessary (Edit: the author of the accepted answer added the iframe section after I wrote this). You just have to include embed the output as an <iframe>:
from flask import Flask, render_template, Response
import time, math
app = Flask(__name__)
#app.route('/content')
def content():
"""
Render the content a url different from index
"""
def inner():
# simulate a long process to watch
for i in range(500):
j = math.sqrt(i)
time.sleep(1)
# this value should be inserted into an HTML template
yield str(i) + '<br/>\n'
return Response(inner(), mimetype='text/html')
#app.route('/')
def index():
"""
Render a template at the index. The content will be embedded in this template
"""
return render_template('index.html.jinja')
app.run(debug=True)
Then the 'index.html.jinja' file will include an <iframe> with the content url as the src, which would something like:
<!doctype html>
<head>
<title>Title</title>
</head>
<body>
<div>
<iframe frameborder="0"
onresize="noresize"
style='background: transparent; width: 100%; height:100%;'
src="{{ url_for('content')}}">
</iframe>
</div>
</body>
When rendering user-provided data render_template_string() should be used to render the content to avoid injection attacks. However, I left this out of the example because it adds additional complexity, is outside the scope of the question, isn't relevant to the OP since he isn't streaming user-provided data, and won't be relevant for the vast majority of people seeing this post since streaming user-provided data is a far edge case that few if any people will ever have to do.
Originally I had a similar problem to the one posted here where a model is being trained and the update should be stationary and formatted in Html. The following answer is for future reference or people trying to solve the same problem and need inspiration.
A good solution to achieve this is to use an EventSource in Javascript, as described here. This listener can be started using a context variable, such as from a form or other source. The listener is stopped by sending a stop command. A sleep command is used for visualization without doing any real work in this example. Lastly, Html formatting can be achieved using Javascript DOM-Manipulation.
Flask Application
import flask
import time
app = flask.Flask(__name__)
#app.route('/learn')
def learn():
def update():
yield 'data: Prepare for learning\n\n'
# Preapre model
time.sleep(1.0)
for i in range(1, 101):
# Perform update
time.sleep(0.1)
yield f'data: {i}%\n\n'
yield 'data: close\n\n'
return flask.Response(update(), mimetype='text/event-stream')
#app.route('/', methods=['GET', 'POST'])
def index():
train_model = False
if flask.request.method == 'POST':
if 'train_model' in list(flask.request.form):
train_model = True
return flask.render_template('index.html', train_model=train_model)
app.run(threaded=True)
HTML Template
<form action="/" method="post">
<input name="train_model" type="submit" value="Train Model" />
</form>
<p id="learn_output"></p>
{% if train_model %}
<script>
var target_output = document.getElementById("learn_output");
var learn_update = new EventSource("/learn");
learn_update.onmessage = function (e) {
if (e.data == "close") {
learn_update.close();
} else {
target_output.innerHTML = "Status: " + e.data;
}
};
</script>
{% endif %}

how to send JSON to HTML file using flask?

I'm at a beginner at coding and i'm stuck at the final closing :|
i'm using python 2.7
this is my serever.py
from flask import Flask, render_template,request,jsonify
import requests
import json
import new
app = Flask(__name__)
#serve homepage
#app.route('/', methods=["GET","POST"])
def homepage():
return render_template('page2.html')
#app.route('/page3.html', methods=["POST"])
def result_matchup():
h= request.form['h']
a= request.form['a']
l= request.form['l']
p= request.form['p']
result = json.dumps(new.calc(h,a,l,p))
return render_template('page3.html',result=result)
if __name__ == "__main__":
app.run(debug=True)
when i ask for return result for checking myself, this is the output:
{"f": 197.1, "k": 196}
this is my page3.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<center><h1>Final = {{f}}</h1></center>
</body>
</html>
the output for all this is
"Final = "
,while I expect for Final = 197.1.
what am I doing wrong? any help?
thanks!
I assume new.calc returns a dictionary. No need to use json.dumps to stringify that before passing to your template. So instead try:
result = new.calc(h,a,l,p)
result should now be a dictionary, with the keys 'f' and 'k'
Therefor in the template you should access this dictionary, as you would in python:
<center><h1>Final = {{result['f']}}</h1></center>
I would also advise using a later version of python since 2.7 is unsupported now, and making this change early will prevent you having to make already written code, 3.x compatible later.
Two suggestions:
You serialize your result as JSON writing result = json.dumps(new.calc(h,a,l,p)). However, you should directly pass a Python object to render_template. In fact, that's one of the strengths of Jinja templating: You do not need to pass JSON, but you can handle Python objects directly. So just write result = new.calc(h,a,l,p).
Second, within the Jinja template, you have to access the objects as you passed them through your render_template function. In your case, <center><h1>Final = {{result['f]}}</h1></center> should do the job.

Read Flask variable from Javascript

I am doing a CTF challenge, but my question is not about how to solve it, rather the syntax. The challenge is to read the secret key in Flask server's configuration. It is stored in the app.secret_key variable and I want to alert it on the screen by XSS.
Question: how can I access that variable in Flask code from javascript and put it in <script>alert(variable)</script> snippet?
I tried <script type="text/javascript">let v="{{=app.secret_key}}"; alert(v); </script> but it gave Internal Server Error.
First, it must be said, in general you should should absolutely not do this. app.secret_key should never, ever be exposed publicly and should be regarded as a closely guarded secret. Hence the name. But since you're doing this for presumably good reasons involving your game, let's continue.
Probably the simplest way to expose Python variables to JavaScript is directly in the template by dumping JSON. Consider this code:
import json
from flask import Flask, render_template
app = Flask(__name__)
app.secret_key = 'THIS IS SECRET'
#app.route('/')
def hello_world():
server_vars = {
'secretKey': app.secret_key,
'favoriteFoods': ['Eggs', 'Spam']
}
return render_template(
'hello.html',
server_vars=json.dumps(server_vars)
)
if __name__ == '__main__':
app.run()
We're rendering the template hello.html and sending it a template variable, server_vars, which is a rendered JSON string of the same server-side variable, which is a dictionary. This enables us to send any number arbitrary JSON-compatible variables to JavaScript. See hello.html:
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<script>
window.serverVars = {{ server_vars | safe }};
alert(window.serverVars.secretKey)
console.log('btw, my favorite foods are', window.serverVars.favoriteFoods)
</script>
</body>
</html>
Notice that in addition to sending secretKey, we actually sent a Python list, which was converted into an array in JavaScript.

Passing a variable received by flask through HTTP post to JavaScript in html template on flask?

So I'm creating a python app that counts detected objects using OpenCV then passing the counter variable to Flask server using the following HTTP post request:
requests.post('http://127.0.0.1:5000', json = {'count': count})
, the flask sever receives the variable then pass it to a JavaScript within the html template, here is the code of flask server:
app = Flask(__name__)
#app.route("/",methods=['GET', 'POST'])
def index():
content = request.get_json(silent=True)
if content :
cnt = content.get('count') #get JSON from OpenCV every time the count is updated
print cnt # here it prints the variable to the cmd and show me the count update
return render_template("test.html", cnt = cnt); #here the value is passed as zero ?!
if __name__ == "__main__":
app.run(debug=True)
and when I run the 'test.html' template it only show me the 'cnt' variable = 0, although I'm getting the updated value constantly from my OpenCV code to my flask server.
here is the script part of my 'test.html'
<p>People count: <span id="counti"></span></p>
<script>
var countn = '{{cnt}}';
document.getElementById('counti').innerHTML = countn
</script>
I want my 'count' variable to pass smoothly from OpenCV and receive into my Javascript to be able to make my web-app able to make decisions based on the count of objects observed by OpenCV.
What is the optimal way to do this ?
I really appreciate your help!

Django AJAX returns undefined instead of the variables

So I have a simple Django script which I've found online for an AJAX function that runs a Python script and gets the output via stdout.
views.py
from django.shortcuts import render
def index(request):
return render(request,'homepage/page.html')
homepage/page.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
$(function()
{
$('#clickme').click(function(){
alert('Im going to start processing');
$.ajax({
url: "static/homepage/js/external_func.py",
type: "POST",
datatype:"json",
data: {'key':'value','key2':'value2'},
success: function(response){
console.log(response.keys);
console.log(response.message);
}
});
});
});
</script>
</head>
<body>
<button id="clickme"> click me </button>
</body>
</html>
So you can see my url is linked to external_func.py which runs after the button is clicked. The script then returns a json.
external_func.py
import sys
import json
import cgi
fs = cgi.FieldStorage()
sys.stdout.write("Content-Type: application/json")
sys.stdout.write("\n")
sys.stdout.write("\n")
result = {}
result['success'] = True
result['message'] = "The command Completed Successfully"
result['keys'] = ",".join(fs.keys())
d = {}
for k in fs.keys():
d[k] = fs.getvalue(k)
result['data'] = d
sys.stdout.write(json.dumps(result, indent=1))
sys.stdout.write("\n")
sys.stdout.close()
However, when I run the server and clicked on the button, the console shows undefined for both values, meaning response.keys and response.message is undefined.
Now, when I instead switch the code to console.log(response) in homepage/page.html. The console prints out the entire external_func.py code in text.
I couldn't find a solution online. It seems like people rarely calls a Python script in an AJAX request, I see a lot of forum posts about AJAX calling for a php code instead.
EDIT1:
I have to clarify one thing. This is just a small section of my project which I want to run some test on. In my actual project, I will have a function in python that takes a long time to compute, hence I prefer to have a webpage partially rendered with a waiting icon while the function processes. The output from the function will then be displayed on a webpage.
You have a django app, and yet you are using CGI for this function? Why? Why not simply make the function another django view? Serving your response with django is much superior to CGI, unless that function significantly bloats or slows down your django. It is as easy as this:
from django.http import JsonResponse
def func(request):
result = ...
return JsonResponse(result)
If you really want to separate this into a CGI script, the most likely reason you are failing to get a response is your web server not being configured to process the CGI request. (Your Developer Tools Network tab is a great help for diagnosing exactly what kind of response you got.) For security reasons CGI is not enabled by default. You need to tell Apache (or whatever web server you are using) that CGI should be enabled for that directory, and that it should be associated with .py files.

Categories

Resources