How to run flask socket.io on localhost (xampp) - python

The tutorials I have seen use the following code to run the server:
if __name__ == '__main__':
socketio.run(app)
My __init__.py file is:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy.orm import sessionmaker
from sqlalchemy import *
from flask.ext.socketio import SocketIO, emit
app = Flask(__name__)
socketio = SocketIO(app)
app.debug = True
engine = create_engine('mysql://root:my_pw#localhost/db_name')
DBSession = sessionmaker(bind=engine)
import couponmonk.views
My views.py file contains all the #app.route and #socketio decorators.
My question is, where should I be placing the code:
socketio.run(app)
When I put it in the __init__.py_ file, I receive the errors:
File "/opt/lampp/htdocs/flaskapp/flask.wsgi", line 7, in <module>
from couponmonk import app as application
File "/home/giri/Desktop/couponmonk/venv/couponmonk/__init__.py", line 14, in <module>
socketio.run(app)
File "/home/giri/Desktop/couponmonk/venv/lib/python2.7/site-packages/flask_socketio/__init__.py", line 411, in run
run_with_reloader(run_server)
File "/home/giri/Desktop/couponmonk/venv/lib/python2.7/site-packages/werkzeug/serving.py", line 632, in run_with_reloader
return run_with_reloader(*args, **kwargs)
File "/home/giri/Desktop/couponmonk/venv/lib/python2.7/site-packages/werkzeug/_reloader.py", line 231, in run_with_reloader
sys.exit(reloader.restart_with_reloader())
SystemExit: 2

Author of Flask-SocketIO here.
Unfortunately this extension cannot work with a standard web server, you will not be able to host an app that uses it over apache/mod_wsgi. You need to use a gevent server, and not a generic one, but one that is customized for Socket.IO.
That means that Apache is out (it does not even support WebSocket traffic). Also uWSGI is out (supports gevent, but not possible to use a custom gevent server). As a side note, Python 3 is also currently out, as gevent only runs on Python 2 (though I think there's going to be good news about this soon, I'm working on some ideas to get socketio running on Python 3 right now).
The choices that you have are given in the documentation. Summary:
socketio.run(app), which runs the custom socketio gevent server directly.
Gunicorn with a custom socketio worker (command line shown in docs)
You can put nginx as reverse proxy in front of your server if you like. The configuration is also shown in the docs.
Good luck!

Seems lime you are trying to use Miguel's Flask-socketIO extension, right? It only supports Guinicorn as the WSGI server, and advice you to use NGINX as a proxy pass. I know nothing about xampp but as far as I have read; It's possible to do a proxy pass since one of the latest versions of Apache. Have not tried though.

Related

Flask, FlaskSocketIO - RuntimeError: Cannot obtain socket from WSGI environment

When I try to use the functionality that uses websockets in my application, I get this error in the console:
File "/Users/user/venv/lib/python3.7/site-packages/simple_websocket/ws.py", line 138, in __init__
raise RuntimeError('Cannot obtain socket from WSGI environment.')
RuntimeError: Cannot obtain socket from WSGI environment.
I also get this error in the browser console:
WebSocket connection to 'ws://localhost:5000/socket.io/?EIO=4&transport=websocket&sid=40NYzDgGYStMR0CEAAAJ' failed:
I tried using gevent, gevent-websocket, and eventlet, but this created other issues, and I'm not sure that I need to use gevent or eventlet for this use case.
Here's the rest of the relevant code:
__ init __.py
from flask_socketio import SocketIO
...
socketio = SocketIO()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
socketio.init_app(app, cors_allowed_origins='*')
...
return app
app.py
from app import create_app, socketio
app = create_app()
if __name__ == '__main__':
socketio.run(app)
routes.py
This only accepts POST requests because I send data to this route from a Celery task
from app import socketio
...
#main_bp.route('/send_message', methods=['POST'])
def send_message():
...
socketio.emit('test_message', {'msg':'Test'}, namespace='/test')
return 'Results Sent'
index.html
var socket = io.connect('http://localhost:5000/test');
socket.on('connect', function(){
console.log('Connected to socket')
});
socket.on('test_message', function(message){
console.log('Received test message');
}
)
Note that in the browser console I'll see "Connected to socket", but not "Received test message"
You are using the simple-websocket package. This package has a list of supported web servers. The error indicates that you are using a web server that is not in the supported list.
Supported web servers are:
The Flask dev server (for development purposes only, of course)
Gunicorn
Eventlet
Gevent
From this list, it seems your only choice for a production web server is Gunicorn, since you say that eventlet/gevent won't work for your needs.
The use of Gunicorn is covered in the documentation. In that section, simple-websocket is the third option mentioned. Here is the example start up command:
gunicorn -w 1 --threads 100 module:app
Maybe you can turn on the logger and the engine.io logger. that qould give you an idea what is the issue.
don't use eventlet and gevent together. use anyone and uninstall the other.

Using flask-socketio, how can I asynchornously emit multiple messages in one function?

I'm building a Flask web app using the flask-socketio module to implement websockets. It generally works fine, but when I try to emit multiple messages from the server to the client in a for loop, all the messages are actually sent at once - that is, as soon as all of them have been created.
I read that the solution might be to use an eventlet server capable of asynchronous task handling:
"The simplest deployment strategy is to have eventlet or gevent installed, and start the web server by calling socketio.run(app) as shown in examples above. This will run the application on the eventlet or gevent web servers, whichever is installed." (taken from the Flask-SocketIO docs)
Sadly, that doesn't solve the problem. I've never worked with websockets before, so I'm a bit lost. Here is a simplified version of my code:
from flask import Flask
from flask_socketio import SocketIO, emit
import eventlet
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on("connect")
def handle_connect():
print("server and client connected")
#socketio.on("text")
def text(question):
for _ in range(3):
answer = my_module.generate_answer(question)
emit("message", {"msg": answer})
socketio.run(app)
Just assume that my_module.generate_answer() generates a sentence based on some user input sent via the websocket. Each generation takes 5-10 seconds. That's also the reason why I want the answers to be sent via a WebSocket once they're generated - my frontend could already display the first answer while waiting for the next ones.
Thank you so much for your help!
You need to monkey patch at the very top of your file.
Your import statements should look like this:
import eventlet
eventlet.monkey_patch()
from flask import Flask
from flask_socketio import SocketIO, emit

Serving dynamic files on heroku?

I have a flask app that has two threads. One modifies flask templates to keep them up to date from scraped info, and the other is the flask server that takes incoming route requests.
from flask import Flask, render_template
import threading
import RunArbIfDown
app = Flask(__name__, static_url_path='')
#app.route('/')
def index():
return render_template('index.html')
if __name__ == "__main__":
threading.Thread(target=app.run).start()
threading.Thread(target=RunArbIfDown.start).start() # this line continuously updates index.html (every 60s)
When I check the app, index.html is never updated even though there seem to be no errors. Are we allowed to modify files on the heroku dyno? Are there any good solutions for this?
Running threads in a WSGI environment might yield unexpected results. The WSGI server usually manages threads and can create and kill them at any time.
Also you have protected your threading code with a __name__ condition. The code will execute if the file is started directly. A WSGI server will not do that. It will import the file and the the condition will not be met.
A typical way to run recurring tasks in Flask is to use a custom command via cron. It is run as a separate process.

How do I run twisted with flask?

I want to be able to run twisted servers on multiple different directories (exp: /example1, /example2...etc), So I thought I'd use flask. Here is what I have so far:
from flask import Flask
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
from twisted.internet import reactor
from twisted.web.proxy import ReverseProxyResource
from twisted.web.resource import Resource
app = Flask(__name__)
#app.route('/example1')
def index():
return 'My Twisted Flask'
flask_site = WSGIResource(reactor, reactor.getThreadPool(), app)
root = Resource()
root.putChild('my_flask', flask_site)
site_example = ReverseProxyResource('www.example.com', 80, ''.encode('utf-8'))
root.putChild('example1', site_example)
reactor.listenTCP(80, Site(root))
reactor.run()
The only problem is that it doesn't work, I'm not sure what I'm doing wrong. I appreciate any help, thanks!
My personal opinion: running Flask in Twisted's reactor isn't a good idea because Twisted's reactor is blocked when a request is processed by Flask.
I think you might be interested in Klein, which provided API similar to Flask, but works on Twisted out of the box: http://klein.readthedocs.io/en/latest/
Another option: I'd take a look into nginx as a reverse proxy for Flask applications instead of Twisted. nginx runs in a separate process and isn't blocked while a request is processed by Flask.
https://www.nginx.com/resources/admin-guide/reverse-proxy/
You can use twisted web, as documented on the Flask deploy documentation. Here's how I managed to run a server on my machine:
pip3 install twisted[tls]
export PYTHONPATH=${PYTHONPATH}:${PWD} # exports python path
twistd web -n --port tcp:5000 --wsgi path-to-your-app-root --logfile log.txt
Though I've had some issues with the server after it's up and running for my particular scenario, this might work for you

arduino yun uhttpd flask setup

I'm trying to set up python and flask on the arduino yun. I've managed to run python files via the /etc/config/uhttpd configuration file:
...
list interpreter ".py=/usr/bin/python"
...
The default path for the website's root is: /www in which I've placed a soft link (apps) to the sd card. So now I can run python programs: http://[ip arduino]/apps/helloworld.py
And when I make my first helloflask.py program and run that via python helloflask.py I can see the result at: http://[ip arduino]:5000
But now I want to configure the uhttpd mini webserver (which is capable to exchange information via CGI) to use the flask setup. The URI: http://flask.pocoo.org/docs/deploying/cgi/#server-setup shows some instructions... but I just don't get it. I've made a directory ../apps/uno in which I've placed a __init__.py file with the following content:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "He Flask!"
In the apps dir I've put a file: cgi.py with this content:
from wsgiref.handlers import CGIHandler
from uno import app
CGIHandler().run(app)
Now I when I browse: http://[ip arduino]/cgi.py get a server error occured, contact the administrator (I think this is the CGI interface from uhttpd).
I just don't grasp the CGI configuration for Flask/uhttpd
I looked into this too and got a little further, I was able to setup a simple hello world but once I tried to do something non-trivial I ran into a big issue that uhttpd doesn't support URL rewriting/aliasing. This means your flask app can only be served at the URL of its .py file instead of at a root like http:// (arduino IP) /flaskapp/. None of the routes inside the app will be visible and makes the whole thing unusable.
However, instead of trying to force flask into uhttpd I had great success running the built in server that flask provides. Take a look at this guide I wrote up that uses flask to serve data from a Yun: https://learn.adafruit.com/smart-measuring-cup/overview
The thing to do is add a call to app.run when the script is run, for example make your flask app look like:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello Flask!"
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, threaded=True)
Then log in to the Yun and run the script using python. Flask's built in server should start serving the app on http:// (arduino IP) :5000/. Make sure to include the host='0.0.0.0' as it's required to listen on the Yun's external network interface. You probably also want debug=True so there are better error messages (and live reloading of the server when the code changes), and I found threaded=True helps because the default server only handles one connection at a time. The Yun is a relatively slow processor so don't expect to service a lot of concurrent requests, however it's quite capable for providing a simple REST API or web application for a few users.
If you want this server to always run on bootup, edit the /etc/rc.local file to include a call to python and your script.

Categories