How to run Flask SocketIO in a thread? - python-3.x

I'm trying to run Flask SocketIO in thread using Python 3 and I cannot get it to work.
My code will not continue in my while loop.
How can I run it in thread?
import threading
from flask import Flask, render_template, request, redirect, url_for
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
#turn the flask app into a socketio app
socketio = SocketIO(app)
#app.route("/")
def index():
return render_template('index.html', **templateData)
if __name__ == "__main__":
threading.Thread(target=socketio.run(app),kwargs=dict(debug=False, use_reloader=False,host='0.0.0.0', port=5000)).start()
sleep(2)
while True:
try:
Print("Hello I'm in a while loop")
except KeyboardInterrupt:
sys.exit()

you should pass socketio.run as target, and app as argument
threading.Thread(
target=socketio.run,
args=(app,),
kwargs=dict(debug=False, use_reloader=False,host='0.0.0.0', port=5000)
).start()
also seems like you forget to import sleep from time
from time import sleep
and also please notice that templateData is not defined in code

Related

Python flask mqtt socketio and subscribing on startup

When starting a flask, mqtt and socketio app how exactly can I subscribe to topics when the app starts but before the browser connects for the first time?
I had assumed I could use before_first_request but that only gets called on first request, also assume I could use mqtt.on_connect but that is never called when using socket io and if I subscribe before starting the app in __main__ then I get two threads subscribed rather than one.
#!/usr/bin/env python3
import json
from flask import Flask, render_template
from flask_mqtt import Mqtt
from flask_socketio import SocketIO
from flask_bootstrap import Bootstrap
# Flask App
app = Flask(__name__)
app.config['MQTT_BROKER_URL'] = '192.168.109.135'
print('Configured MQTT IP Address: ' + app.config['MQTT_BROKER_URL'])
mqtt = Mqtt(app)
socketio = SocketIO(app)
#app.route("/")
def roots():
return render_template('index.html')
#app.route('/mqtt')
def mqtt_index():
return render_template('mqtt.html')
#socketio.on('subscribe')
def handle_subscribe(json_str):
print('Subscribe ' + json_str)
#socketio.on('unsubscribe_all')
def handle_unsubscribe_all():
print('Socket IO unsubscribe all')
mqtt.unsubscribe_all()
#socketio.on('connect')
def handle_connect():
print('Socket IO Connected')
#socketio.on('discconnect')
def handle_connect():
print('Socket IO Discconnect')
#mqtt.on_connect()
def handle_mqtt_connect():
print('MQTT Connected')
#mqtt.on_message()
def handle_mqtt_message(client, userdata, message):
print('MQTT Message')
data = dict(
topic=message.topic,
payload=message.payload.decode(),
qos=message.qos,
)
print(mqttresponse)
socketio.emit('mqtt_message', data=data)
#mqtt.on_log()
def handle_logging(client, userdata, level, buf):
print('MQTT log', level, buf)
pass
#app.before_first_request
def before_first_request():
print("before_first_request")
mqtt.subscribe('homeassistant/+/+/set', 0)
if __name__ == "__main__":
# Main http web server for firmware downloading and the main frontend.
socketio.run(app, host='0.0.0.0', port='6080', use_reloader=True)
Any ideas where the mqtt.subscribe should go so it subscribes to the topics I want before the first connect to the webserver?
I found there is already a related issue which is the on_connect callback doesn't get called, and a question on here too. So this is a duplicate.
Flask MQTT on_connect is never called when used with SocketIO
https://github.com/stlehmann/Flask-MQTT/issues/82

Google Drive API Webhook

I have set up a google drive webhook through the "watch property"(https://developers.google.com/drive/api/v2/reference/files/watch) and it is working well and submitting a response as soon as any changes are detected on the watch file. However, the request body (i.e.posted_data=request.get_data( )) as below comes back empty (i.e. None). I have tried other options such as request.json but still empty. Does anyone have any ideas on what I am possibly doing wrong? My Python Flask webhook code is below and works well (i.e. any file updates are posted) except that it returns an empty data type (i.e.posted_data=request.get_data( ) is None). Any suggestions are highly appreciated!
from datetime import datetime
from flask import Flask, request, jsonify
import pytz
def get_timestamp():
dt=datetime.now(pytz.timezone('US/Central'))
return dt.strftime(("%Y-%m-%d %H:%M:%S"))
app = Flask(__name__)
#app.route('/webhook', methods=['POST','GET'])
def webhook():
if request.method=='GET':
return '<h1> This is a webhook listener!</h1>'
if request.method == 'POST':
posted_data=request.get_data( )
print("We have received a request =====>",posted_data)
cur_date=get_timestamp()
print("Date and time of update ====>",cur_date)
http_status=jsonify({'status':'success'}),200
else:
http_status='',400
return http_status
if __name__ == '__main__':
app.run(port=5000)
The above code works except that google will post their response as headers (i.e. request.headers). See updated code below.
from datetime import datetime
from flask import Flask, request, jsonify
import pytz
def get_timestamp():
dt=datetime.now(pytz.timezone('US/Central'))
return dt.strftime(("%Y-%m-%d %H:%M:%S"))
app = Flask(__name__)
#app.route('/webhook', methods=['POST','GET'])
def webhook():
if request.method=='GET':
return '<h1> This is a webhook listener!</h1>'
if request.method == 'POST':
print(request.headers)
cur_date=get_timestamp()
print("Date and time of update ====>",cur_date)
http_status=jsonify({'status':'success'}),200
else:
http_status='',400
return http_status
if __name__ == '__main__':
app.run(port=5000)

Exception has occurred: NotImplementedError

Executed this for the first time and getting exception at app.listen(port)
import tornado.web
import tornado.ioloop
class basicRequestHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, World this is a python command executed from the backend.")
if __name__ == "__main__":
app = tornado.web.Application([
(r"/", basicRequestHandler)
])
port = 8882
app.listen(port)#Getting exception here
print(f"Application is ready and listening on port {port}")
tornado.ioloop.IOLoop.current().start()
in python 3.8:
import tornado.ioloop
import tornado.web
import asyncio
class basicRequestHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, World this is a python command executed from the backend.")
if __name__ == "__main__":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
app = tornado.web.Application([
(r"/", basicRequestHandler)
])
port = 8882
app.listen(port)
print(f"Application is ready and listening on port {port}")
tornado.ioloop.IOLoop.current().start()
#gdi313's answer is correct, but let me explain why we have to include asyncio into our code,
till python3.7 Tornado selects 'WindowsSelectorEventLoop' as default, whereas python 3.8 default is not compatible with windows
Thats is why if your application runs on windows using tornado have to have line
"asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())" at the beginning
Hope this is useful to someone who is facing the error!
https://github.com/tornadoweb/tornado/pull/2686/files

Flask-SocketIO emit not working from different module?

When I invoke socket.emit('someevent','blahblah') from server.py file, everything works as intended. But when I try to invoke the same method from bot.py, nothing happens.
Code:
server.py:
import eventlet
eventlet.monkey_patch()
import eventlet.wsgi
from flask import Flask, render_template, jsonify, request, abort
from flask_cors import CORS, cross_origin
import threading
from thread_manager import ThreadManager
from flask_socketio import SocketIO, emit, send
cho = Flask(__name__, static_folder="client/dist", template_folder="client/dist")
socketio = SocketIO(cho)
cors = CORS(cho)
threadmanager = ThreadManager() # Start the thread manager
import bot as bot_module
#cho.route('/api/start_bot', methods=['POST'])
#cross_origin()
def startBot():
"""
Begins the execution
:return:
"""
if request.method == 'POST':
request_json = request.get_json()
.... more code
bot = bot_module.Bot(some_args_from_request_above)
bot_thread = threading.Thread(target=bot.run)
bot_thread.start()
if threadmanager.check_thread_status(bot_name):
print('Thread is alive!')
return ok_res
else:
print('Thread seems inactive')
return bad_res
if __name__ == "__main__":
eventlet.wsgi.server(eventlet.listen(('0.0.0.0', 5000)), cho, debug=True)
bot.py
import server
class Bot:
.....
def run(self):
server.socketio.emit('someevent', 'w0w') # <-- nothing happens
I know I'm using the standard threading mechanism but it seems to not be related to threads whatsoever as I can create a random static method inside the Bot class, invoke it before creating a separate thread from the main file and nothing will happen. The thread_manager module contains nothing that would interfere, but I've even removed it completely from the picture and nothing changed. Any clues?
Turns out this was completely related to the circular import. Splitting the app declaration from the entrypoint worked, so that I'd have a third reference file which to import socketio from.

how to use epoll on tornado

i am trying to make epoll work on tornado
import tornado.ioloop
import tornado.web
from tornado.platform.epoll import EPollIOLoop
from tornado import web, gen
class MainHandler(tornado.web.RequestHandler):
#web.asynchronous
#gen.engine
def get(self):
self.write("Hello, world")
application = tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
application.listen(8888)
EPollIOLoop().start()
but when i start the program and visit the url localhost:8888/ it didn't return anything.
is that my system didn't meet the requirement?my linux version was Ubuntu 12.04.1 LTS.
Just use tornado.ioloop.IOLoop.instance(). It choose best IOLoop for your platform.
if __name__ == "__main__":
application.listen(8888)
ioloop = tornado.ioloop.IOLoop.instance()
print ioloop # prints <tornado.platform.epoll.EPollIOLoop object at ..>
ioloop.start()
You should call self.finish() if you use asynchronous decorator:
If this decorator is given, the response is not finished when the
method returns. It is up to the request handler to call self.finish()
to finish the HTTP request. Without this decorator, the request is
automatically finished when the get() or post() method returns.
class MainHandler(tornado.web.RequestHandler):
#web.asynchronous
#gen.engine
def get(self):
self.write("Hello, world")
self.finish()

Resources