Change state of global instance from flask-socketio on message - python

I'm currently running flask-socketio inside to a thread. On a specific socketio event, I want to change the state of a global object in main thread i.e, perform a function which might change its instance variable's values
In my actual program, 'self.params' is a list of chromedrivers. When a signal is emited a driver is removed or added. Does that make a difference? Chromedriver is a un-picklable object.
Here's a flask socketio code which a simplified sample:
from gevent import get_hub
get_hub().NOT_ERROR += (KeyboardInterrupt,)
from flask import Flask
from flask_socketio import SocketIO, emit
import threading
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecret'
socketio = SocketIO(app, cors_allowed_origins="*")
class SomeObj():
def __init__(self, param):
self.param = param
def query(self):
self.param += 1
return
global_obj = SomeObj(0)
#socketio.on('msg')
def handle_msg():
global_obj.query()
def start():
def run():
socketio.run(app, port=5005)
SocketIOThread = threading.Thread(target=run)
SocketIOThread.daemon = True
SocketIOThread.start()
if __name__ == '__main__':
start()
while True:
a = input()
if a == '`':
break
else:
print(global_obj.param)
How can i achive this? I get only 0 every time.

Related

How to exit the previously opened function created from socketio.start_background_task() when new connection is being made

Every time when I refresh the page from client side a new connection is made with the flask server and it runs the function 'backgroundFunction()' without exiting the recent opened function and the number increases as I refresh the page again and again.
from flask import Flask
from flask_socketio import SocketIO, send, emit
import socket
from time import sleep
import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['DEBUG'] = True
socketio = SocketIO(app , cors_allowed_origins="*" , async_mode = None , logger = False , engineio_logger = False)
def backgroundFunction():
while True:
data = "I am Data"
socketio.emit('data', data, broadcast=True)
socketio.sleep(2)
#socketio.on('connect')
def socketcon():
print('Client connected')
socketio.start_background_task(backgroundFunction)
if __name__ == ("__main__"):
socketio.run(app, port=5009)
Look at the example code in the Flask-SocketIO repository to learn one possible way to implement a background job that starts the first time an event is triggered.
Code is here. Here is the relevant excerpt:
thread = None
thread_lock = Lock()
def background_thread():
"""Example of how to send server generated events to clients."""
count = 0
while True:
socketio.sleep(10)
count += 1
socketio.emit('my_response',
{'data': 'Server generated event', 'count': count})
#socketio.event
def connect():
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(background_thread)

How to us an arg given to Flask app.config inside a route function?

My webapp runs from inside a function because im multithreading with other functions (only 1 instance of flask), and my questions are:
A. What is the best way to pass a Queue into the app?
B. When passed, how can the Queue be used inside a specific route?
Here is the relevant part of the code ive written so far, which gives and error "global name 'queue' is not defined" when a request is made to "/parser".
app = Flask(__name__)
q = Queue()
app.config['queue'] = q;
#app.route('/parser')
def Parser():
arg = request.args.get('arg') #if key doesn't exist, returns None
queue.put(arg)
def Run():
app.run(debug=False, host='0.0.0.0')
if __name__ == '__main__':
q = Queue()
app.config['queue'] = q;
thread = Thread(target = Run)
thread.start()
Thanks in advance :)
Edit: Added a code sample that might be of help
from flask import Flask
from threading import Thread
from queue import Queue
app = Flask(__name__)
q = Queue()
app.config['queue'] = q;
app.config['test'] = 'testing';
#app.route('/insert/<var>')
def Insert(var):
q = app.config['queue']
q.put(var)
return "Ok"
#app.route('/pop')
def Get():
q = app.config['queue']
return q.get()
def Run():
app.run(debug=False, host='0.0.0.0')
if __name__ == '__main__':
thread = Thread(target = Run)
thread.start()
I am pretty sure that flask does not support running the same app instance in multiple threads.
I have a feeling that this is an instance of XY problem,
If you are deploying on production, this page lists some ways to do so that can handle multiple concurrent connections.

How can I run a python script from within Flask

I have a Flask script which creates a website and prints some data dynamically. - The data which it prints should come from another python script.
The current problem that I'm facing is that if I put the line that executes the python script before the line that executes the Flask app, it will run the Python script without running Flask; and vice versa.
Python script:
import websocket
from bitmex_websocket import Instrument
from bitmex_websocket.constants import InstrumentChannels
from bitmex_websocket.constants import Channels
import json
websocket.enableTrace(True)
sells = 0
buys = 0
channels = [
InstrumentChannels.trade,
]
XBTUSD = Instrument(symbol='XBTUSD',
channels=channels)
XBTUSD.on('action', lambda msg: test(msg))
def test(msg):
parsed = json.loads(json.dumps(msg))
print(parsed)
XBTUSD.run_forever()
Flask script (NB: price should be the variable 'parsed' from the other script):
# Start with a basic flask app webpage.
from flask_socketio import SocketIO, emit
from flask import Flask, render_template, url_for, copy_current_request_context
from random import random
from time import sleep
from threading import Thread, Event
import requests, json
import time
__author__ = 'slynn'
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
#turn the flask app into a socketio app
socketio = SocketIO(app)
#random number Generator Thread
thread = Thread()
thread_stop_event = Event()
class RandomThread(Thread):
def __init__(self):
self.delay = 1
super(RandomThread, self).__init__()
def randomNumberGenerator(self):
while not thread_stop_event.isSet():
socketio.emit('newnumber', {'number': parsed}, namespace='/test')
sleep(self.delay)
def run(self):
self.randomNumberGenerator()
#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 = RandomThread()
thread.start()
#socketio.on('disconnect', namespace='/test')
def test_disconnect():
print('Client disconnected')
if __name__ == '__main__':
socketio.run(app)
Using import:
Wrap what the python script (e.g. website_generator.py) is generating into a function.
Place it in the same directory as your app.py or flask.py.
Use from website_generator import function_name in flask.py
Run it using function_name()
You can use other functions such as subprocess.call et cetera; although they might not give you the response.
Example using import:
from flask import Flask
import your_module # this will be your file name; minus the `.py`
app = Flask(__name__)
#app.route('/')
def dynamic_page():
return your_module.your_function_in_the_module()
if __name__ == '__main__':
app.run(host='0.0.0.0', port='8000', debug=True)
try this:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def run_script():
file = open(r'/path/to/your/file.py', 'r').read()
return exec(file)
if __name__ == "__main__":
app.run(debug=True)

socketio.emit() not making it to the user when called from monkey patched gevent thread

I have code that can send messages up to a connected user with socketio.emit(), but when doing the same thing from a gevent thread, the data never makes it to the client.
Sample code:
from flask import Flask, request, render_template
from flask_socketio import SocketIO, join_room, leave_room, emit
import gevent
from gevent import monkey
monkey.patch_all()
app = Flask(__name__)
app.config['SECRET_KEY'] = '<redacted>'
app.debug = False
socket = SocketIO(app, async_mode="gevent")
def sendStamina(sessionId, stamina):
# have to use socket.emit here, simply because this function is called from an BG thread.
with app.test_request_context('/'):
socket.emit('stamina', {'sessiondId': sessionId, 'stamina': stamina}, room=sessionId)
print("sent satmina update")
def stamina_update():
print("stamina update called")
next_call = time.time()
while 1:
print("stamina update called inside")
next_call = next_call + 1
gevent.sleep(next_call - time.time())
sendStamina(<data>, <data>)
t1 = gevent.spawn(game.stamina_update)
t2 = gevent.spawn(start_server)
gevent.joinall([t1, t2])
I've seen a few threads about this on SO and socketio's forums, and it's gotten me closer, but I'm still missing something...

Python-SocketIO server won't emit from the main section of the program

I have a pyhton-socketio server that servers on port 8000 and handles connections perfectly. I want to emit the following emit message every 2 seconds. When emitting the client doesn't receive a message. If I emit from where I point out in the comment it works perfect.
How can I edit this to be able to emit from inside the while loop successfully?
The python server code:
import socketio
import eventlet
import threading
import time
from flask import Flask, render_template
sio = socketio.Server()
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
# as a decorator:
#sio.on('connect')
def connect_handler(sid, environ):
print('IP->' + environ['REMOTE_ADDR'])
# If I emit here it works e.g. sio.emit('status-update', {'core0_in': 8, 'core1_in': 12,'cpu_usage_in': 5, 'users': 7})
#sio.on('disconnect')
def disconnect(sid):
print('disconnect ', sid)
class Server(threading.Thread):
def __init__(self, thread_id):
threading.Thread.__init__(self)
self.threadID = thread_id
def run(self):
print("Starting " + self.name)
serve()
def serve():
if __name__ == '__main__':
global app
# wrap Flask application with socketio's middleware
app = socketio.Middleware(sio, app)
# deploy as an eventlet WSGI server
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
server_thread = Server("Server-thread")
server_thread.start()
while True:
print("Emitting...")
sio.emit('status-update', {'core0_in': 8, 'core1_in': 12,'cpu_usage_in': 5, 'users': 7}) # when emitting here the client doesn't receive anything
time.sleep(2)

Categories

Resources