Flask-socketio emit function in OSCserver thread - python

I am creating an Flask-socketio app, in which I want to send socket when an OSC message is received, in order to receive it into a web app thanks to socketio.js
from flask import Flask, render_template, copy_current_request_context, current_app
from flask_socketio import SocketIO, emit, send
from OSC import OSCClient, OSCMessage, OSCServer
import time, threading
app = Flask(__name__)
socketio = SocketIO(app)
client = OSCClient()
client.connect( ("localhost", 62345))
receive_address = ('localhost', 62346)
server = OSCServer(receive_address)
# simple callback functions
def answer_handler(addr, tags, stuff, source):
with app.app_context():
socketio.emit('tempo', 1)
# adding callback functions to listener
server.addMsgHandler("/puredata", answer_handler)
if __name__ == '__main__':
#Start OSCServer in extra thread
st = threading.Thread( target = server.serve_forever )
st.daemon = True
st.start()
print('OSC server is started')
socketio.run(app, host='0.0.0.0')
Even if I don't get error message, the socket is not receive from the javascript side, because the emit function is called in another thread, and there is conflicts with the request context.
I tried several things according to some other stackoverflow tickets :
socketio = SocketIO(app, async_mode='threading')
Adding this line before handler function
#copy_current_request_context
Or recreate a socketio instance into the callback
def answer_handler(addr, tags, stuff, source):
socketio_connection = SocketIO(app)
with app.app_context():
socketio_connection.emit('tempo', 1)
But none of these solution is working, and I need to integrate solve this 'context' problem into my thread.
Note that :
socketio.emit('tempo', 1)
is working great out of this thread , and received in the javascript part

Related

How to do parallel processing while using gevent with WSGIServer?

I am running WSGIServer using gevent but I also want to run a background worker.
from gevent import monkey
from gevent.pywsgi import WSGIServer
from flask import Flask, request,Response
monkey.patch_all()
from threading import Thread
api = Flask(__name__)
my_queue=[1,2,3]
#api.route('/add', methods=['GET'])
def add():
my_queue.append(request.args.get('item'))
return Response("Added!", 200)
def worker(id):
while True:
print(f"{id}-working-{my_queue}")
if __name__ == '__main__':
server = WSGIServer(('0.0.0.0', 5001), api)
server_thread = Thread(target=server.start)
worker1_thread = Thread(target=worker,args=(1,))
worker2_thread = Thread(target=worker,args=(2,))
server_thread.start()
worker1_thread.start()
worker2_thread.start()
If I am running it without monkey.patch_all(), my two worker works in parallel but the API will not respond.
If I use monkey.patch_all() only the first worker will work and the API will also not respond.
How can I get this to work properly?
Also, I am aware I need a lock for the queue but I don't know how to implement it.

How can i invoke a flask endpoint directly from code without using requests

Hey everyone I was tasked a few days ago to create an API style application that listens over a TCP socket for some commands then return some responses mainly success/failures (i know it's dumb but it's the client request) since I have some validation/database stuff I thought of flask directly but I am still stuck on how I am going to invoke the specific endpoints in code directly. here is a small snippet on how I am imagining things would be
from flask import Flask
import threading
data = 'foo'
app = Flask(__name__)
#app.route("/SomeCommand")
def SomeCommand():
return { 'Some' : 'Response'}
def flaskThread():
app.run()
def TcpListenner():
# logic that listens over tcp socket then invoks the flask app
# I was thinking about calling app.something() from here
pass
if __name__ == "__main__":
flaskApp = threading.Thread(target=flaskThread)
flaskApp.start()
listenner = threading.Thread(target=TcpListenner)
listenner.start()
any help/ideas would be much appreciated, thank you
You can use flask_socketio with which the flask app and socket i.e. tcp listener both start together...
Based on what I've understood, you can do something like this:
That the client will first make a connection to the flask socket.
Then, to send a command to the flask app, the client will send a message to the flask socket with the command in its message.
The flask socket will be listening for messages. So when it receives a message for the specific command, then it emits a response based on that command to the socket which will then be received by the client.
Below is an example code for the flask socket app:
import eventlet
eventlet.monkey_patch()
from flask import Flask
from flask_socketio import SocketIO, send, emit
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*", logger=True, engineio_logger=True)
# other flask APIs can come here and can be called by the client...
def someCommandOneResponse(): # function that sends response to client when flask socket gets command 1
commandOneResponse = 'Success'
socketio.emit('message', commandOneResponse)
def someCommandTwoResponse(): # function that sends response to client when flask socket gets command 2
commandTwoResponse = 'Failure'
socketio.emit('message', commandTwoResponse)
#socketio.on('message') # when any command is received on the socket from the client
def handleMessage(cmd):
print('\nCommand Received: ' + cmd + '\n')
if( cmd == 'SomeCommand1' ): # if the client has sent a message for command 1
print('Got Some Command 1')
someCommandOneResponse()
elif( cmd == 'SomeCommand2' ): # if the client has sent a message for command 2
print('Got Some Command 2')
someCommandTwoResponse
send(cmd, broadcast=True)
if __name__ == '__main__':
socketio.run(app, port=3000) # starts the flask socket (tcp listener) as well as the flask app

How can i properly use circular imports in python

Context: I have a websocket 'server.py' and a script that executes some tasks: 'worker.py'. I want to use the functions in server.py to send the results from that task in worker.py. But the thing is, when a client requests the worker to send results, i need to use a function from worker.py. How can I avoid circular dependies in this situation?
Server.py:
import eventlet
#eventlet.monkey_patch()
import socketio
from flask import Flask
from flask_cors import CORS
#The Worker file
import worker
sio = socketio.Server(cors_allowed_origins='http://localhost:8100')
#sio.on('connect')
def connectHandler(sid, environ):
print('[INFO] Incoming connection from: ' + environ['REMOTE_ADDR'])
sio.emit('response', {'data' : 'Connection established, you can now request classifications by firing the "requestClassification" event.'})
#sio.on('disconnect')
def disconnectHandler(sid):
print('disconnect ', sid)
#sio.on('requestClassification')
def requestHandler(data):
print('[INFO] recieved request to classify')
print(data)
#using a function in the worker module
worker.someFunc()
eventlet.wsgi.server(eventlet.listen(('127.0.0.1', 8080)), app)
worker.py:
import server
def work():
while True:
result = doSomeTask()
print(f'sending result: {str(i)}')
server.sio.emit('result', {'data' : result})
server.sio.sleep(1)
How can i properly use the imports without defining sio (the server) twice for example?

How do i run a Python script on a dynamic webpage with Flask and Socketio?

I'm trying to use Flask and SocketIO, i found this example where some random numbers are printed dynamically in real time on a 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
__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):
"""
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("Making random numbers")
while not thread_stop_event.isSet():
number = round(random()*10, 3)
print(number)
socketio.emit('newnumber', {'number': number}, 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)
I have a Python script which connects to a Websocket, receives data and prints this data.
import websocket
from bitmex_websocket import Instrument
from bitmex_websocket.constants import InstrumentChannels
from bitmex_websocket.constants import Channels
import json
websocket.enableTrace(True)
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()
I now want to print this data on my webpage, i tried to "merge" these two scripts but apparently i can't, because to run the Websocket connector i have to run XBTUSD.run_forever(), which will start the process but it won't run the rest of the code, including the Flask part which generates the webpage, so only one at time can run.
Is there a way to make the Websocket connector communicate with the Flask/Socketio part so that the data from the Websocket connector is printed on the webpage?

Send WebSocket message from Flask view

I'm trying to make a Flask app that uses WebSockets. The example from Flask-sockets works but how would I send a message from a regular view?
Similarly to how Flask-SocketIO use .emit() and .send()-methods.
In the example below (from the Flask-Sockets example) I would for instance like to be able to broadcast a message from the hello-view.
from flask import Flask
from flask_sockets import Sockets
app = Flask(__name__)
sockets = Sockets(app)
#sockets.route('/echo')
def echo_socket(ws):
while not ws.closed:
message = ws.receive()
ws.send(message)
#app.route('/')
def hello():
# How can I send a WebSocket message from here?
return 'Hello World!'
if __name__ == "__main__":
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()
You can use a global socket list of all client. Traverse all list and send message to all ws instance.
Example code;
from flask import Flask, render_template
from flask_sockets import Sockets
app = Flask(__name__)
sockets = Sockets(app)
ws_list = []
#sockets.route('/echo')
def echo_socket(ws):
ws_list.append(ws)
while not ws.closed:
message = ws.receive()
ws.send(message)
#app.route('/')
def hello():
# How can I send a WebSocket message from here?
return render_template('index.html')
#app.route('/send_message_to_all_client')
def broadcast():
for ws in ws_list:
if not ws.closed:
ws.send("broadcast message")
else:
# Remove ws if connection closed.
ws_list.remove(ws)
return "ok"
if __name__ == "__main__":
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()

Categories