How can i update global variable outside a thread? - python

I have a global varibale that share for all of function in my flask socketio server and a thread to start another feature to send notification for which connected to flask socketio server. The thread start from running and the global variable is passed into. The problem is when i change the global varibale outside the thread, it's not updated in the thread.
from flask import Flask, request
from flask_socketio import SocketIO, emit
from flask_cors import CORS, cross_origin
from generate_audio import *
from manage_time import receive_data, clock
from manage_audio import set_audio
import threading
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins="*")
CORS(app)
a = 0
#app.route("/demo", methods=["POST"])
#cross_origin(origin='localhost',headers=['Content-Type','Authorization'])
def receive_request():
global a
a += 1
return "Done"
def clock(a):
while True:
print(a)
if __name__ == "__main__":
global a
threading.Thread(target=clock, args=(a,)).start()
socketio.run(app, port=5000, debug=True, host="0.0.0.0")
How can i update a value inside the thread? It's always equal 0, i want it will be increased everytime i send a request to "/demo".

you can modify global variables like this:
global a
a += 1

Related

What is the best way for a Python script to communicate with a Python Flask server that transports content to the client?

The following scenario:
I have a Raspberry Pi running as a server. Currently I am using a Python script with Flask and I can also access the Raspberry Pi from my PC. (The flask server runs an react app.)
But the function should be extended. It should look like the following:
2nd Python script is running all the time. This Python script fetches data from an external API every second and processes it. If certain conditions are met, the data should be processed and then the data should be communicated to the Python Flask server. And the Flask server then forwards the data to the website running on the computer.
How or which method is best to program this "interprocess communication". Are there any libraries? I tried Celery, but then it throws up my second Python script whenever I want to access the external API, so I don't know if this is the right choice.
What else would be the best approach? Threading? Direct interprocess communication?
If important, this is how my server application looks so far:
from gevent import monkey
from flask import Flask, render_template
from flask_socketio import SocketIO
monkey.patch_all()
app = Flask(__name__, template_folder='./build', static_folder='./build/static')
socket_io = SocketIO(app)
#app.route('/')
def main():
return render_template('index.html')
#socket_io.on('fromFrontend')
def handleInput(input):
print('Input from Frontend: ' + input)
send_time()
#socket_io.on('time')
def send_time():
socket_io.emit('time', {'returnTime': "some time"})
if __name__ == '__main__':
socket_io.run(app, host='0.0.0.0', port=5000, debug=True)
Well i found a solution for my specific problem i implemented it with a thread as follows:
import gevent.monkey
gevent.monkey.patch_all()
from flask import Flask, render_template
from flask_socketio import SocketIO
import time
import requests
from threading import Thread
app = Flask(__name__, template_folder='./build', static_folder='./build/static')
socket_io = SocketIO(app)
#app.route('/')
def main():
thread = Thread(target=backgroundTask)
thread.daemon = True
thread.start()
return render_template('index.html')
#socket_io.on('fromFrontend')
def handleInput(input):
print('Input from Frontend: ' + input)
#socket_io.on('time')
def send_time():
socket_io.emit('time', {'returnTime': 'hi frontend'})
def backgroundTask():
# do something here
# access socket to push some data
socket_io.emit('time', {'returnTime': "some time"})
if __name__ == '__main__':
socket_io.run(app, host='0.0.0.0', port=5000, debug=True)

Flask - G variable not accessible in multi threaded context

I am using ThreadPoolExecutor to create threads in my application. When I try to access the Flask g variable in any of the thread pool tasks, it gives me error
RuntimeError: Working outside of application context.
I tried using app.app_context() as well but it fails with error
AttributeError: '_AppCtxGlobals' object has no attribute 'Test'
Is there anyway I can access the g variable in multi-threaded context?
Sample code to reproduce the issue.
from flask import Flask, g
from concurrent.futures import ThreadPoolExecutor
app = Flask(__name__)
if __name__ == '__main__':
app.run('0.0.0.0', port=8000, debug=False)
#app.before_request
def before_req():
g.Test = 'test'
#app.route("/test", methods=["GET"])
def handle_request():
with ThreadPoolExecutor(max_workers=1) as executor:
response = executor.submit(t1)
var = response.result()
print(var)
def t1():
# with app.app_context():
return g.Test

Notification from Flask to JS using socket.IO

I'm using the Flask-SocketIO library which works fine but I need to send a notification with emit to the outside of a socket.io decorator and it's a real pain. Looking at the solutions, many people use rabbitmq or redis but I don't know how to use them.
Here's my code :
from flask import Flask, render_template
from flaskwebgui import FlaskUI
from flask_socketio import SocketIO, emit
app = Flask(__name__)
async_mode = None
app.config['SECRET_KEY'] = 'hello'
socketio = SocketIO(app, async_mode=async_mode, message_queue='amqp:///socketio')
def run_sock():
socketio.run(app, debug=True)
ui = FlaskUI(app, fullscreen=True, server=run_sock,)
#app.route("/")
def index():
return render_template('index.html')
#socketio.on('test', namespace='/test')
def test():
print("test")
if __name__ == "__main__":
ui.run()
io = SocketIO(message_queue='amqp:///socketio')
io.emit('test_emit', {'data': 'toto'}, namespace='/test')
My JS front-end never gets the test_emit message, how do I do?
The problem with your emit is that it appears below the ui.run() call, which does not return until you close the application. Move the emit to any function in your application that executes while the server is running (such as a Flask view function) and it should work just fine.
Why do you have two SocketIO objects in the same process? The socketio instance that you defined near the top of the script can be used anywhere within the process, no need to create a second instance. You do not need to use a message queue for this problem, since you have all the usages of Socket.IO within a single process.

Passing data received from a json request to another function in python flask socketio

I have a python flask app which receives data from json. I have also used socketio and threading in order to process data realtime.
In my program I need to send the data, that I receive from json requests, to another python function.
Below is the code that I wrote to do this: -
from flask_socketio import SocketIO, emit
from flask import Flask, render_template, request, url_for, copy_current_request_context
from random import random
from time import sleep
from pygeodesy.ellipsoidalVincenty import LatLon
from threading import Thread, Event
__author__ = 'shark'
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
# turn the flask app into a socketio app
socketio = SocketIO(app, async_mode=None, logger=True, engineio_logger=True)
# random number Generator Thread
thread = Thread()
thread_stop_event = Event()
#app.route('/platform-data', methods=['POST'])
def platformData():
"""
Generate a random number every 1 second and emit to a socketio instance (broadcast)
Ideally to be run in a separate thread?
"""
# infinite loop of magical random numbers
print("Receiving platform data")
while not thread_stop_event.isSet():
req_data = request.get_json()
id = req_data['id']
latitude = req_data['coordinates'][1]
longitude = req_data['coordinates'][0]
speed = req_data['speed']
angle = req_data['angle']
length = req_data['dimensions'][0]
width = req_data['dimensions'][1]
laneW = req_data['lane_width']
spdLmt = req_data['speed_limit']
return testProcess(speed)
def testProcess(speed):
if speed>30:
print("slow down")
socketio.emit('speed', {'speed': speed}, namespace='/test')
socketio.sleep(.5)
#app.route('/')
def index():
# only by sending this page first will the client be connected to the socketio instance
return render_template('index.html')
#socketio.on('connect', namespace='/test')
def test_connect():
# need visibility of the global thread object
global thread
print('Client connected')
# Start the random number generator thread only if the thread has not been started before.
if not thread.isAlive():
print("Starting Thread")
thread = socketio.start_background_task(platformData)
#socketio.on('disconnect', namespace='/test')
def test_disconnect():
print('Client disconnected')
if __name__ == '__main__':
socketio.run(app)
However, when I run the app and POST data from Postman, I get the below error in my console: -
TypeError: The view function did not return a valid response. The
return type must be a string, dict, tuple, Response instance, or WSGI
callable, but it was a int.
127.0.0.1 - - [05/Mar/2020 17:06:25] "POST /platform-data HTTP/1.1" 500 15625 0.008975
I know the reason for this is that I have declared return testProcess(speed).
Therefore, I need to know the correct way to pass speed variable to 'testProcess' function.
platformData() must return a a string, dict, tuple, Response instance, or WSGI callable but you make return the return of testProcess which is not defined
try:
def testProcess(speed):
if speed>30:
return "slow down"
else:
return "ok"
Or just call testProcess(speed) without return
and then return something else

Long polling chat server

I need some help regarding some minor problems in this chat server I've written. As you can see, I am using a global variable 'chat' to store newly submitted messages. This is because I can't find a working pubsub module for MongoDB (or I just don't know how to use one). Because of this, when 2 people send message almost at the exact same time, only the newer message is being outputted. Here is my current code:
#!/usr/bin/env python
import gevent
import gevent.monkey; gevent.monkey.patch_all()
from gevent.event import Event
from gevent.pywsgi import WSGIServer
from flask import Flask, request, Response, render_template, jsonify
import time
from pymongo import MongoClient
app = Flask(__name__)
app.config['DEBUG'] = True
a = Event()
chat = {}
def logchat(data):
client = MongoClient()
db = client.chatlog
db.bences.insert(data)
#app.route('/output')
def sse_request():
a.wait()
return jsonify(chat)
#app.route('/processchat', methods=['POST'])
def processchat():
global chat
ms = int(round(time.time() * 1000))
chat = {'name': request.form['chatname'], 'msg': request.form['chatmsg'], 'ts': ms}
a.set(); a.clear()
logchat(chat)
return jsonify(success=True)
#app.route('/')
def page():
return render_template('chat.html')
if __name__ == '__main__':
http_server = WSGIServer(('0.0.0.0', 80), app)
http_server.serve_forever()
What can you suggest for me to do? Thanks a lot!

Categories