Connecting Flask Socket.IO Server and Flutter - python

Basically, I have a socket io flask code:
import cv2
import numpy as np
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
from threading import Lock,Timer as tmr
from engineio.payload import Payload
import base64
from PIL import Image
import io
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#socketio.on('connect')
def connect():
print("a client connected")
#socketio.on('disconnect')
def disconnect():
print('Client disconnected')
#app.route('/')
def hello():
return render_template('index.html')
if __name__ == '__main__':
socketio.run(app,port=port,host= '0.0.0.0')
This code is working fine when I try to connect it to javascript
However in flutter I can not achieve that
I have stateful Widget that has a button in it
And I am using this function to connect to my socket when the button is pressed
import 'package:socket_io_client/socket_io_client.dart' as IO;
IO.Socket socket;
connectToSocket() {
socket = IO.io("http://10.0.2.2:6400", <String, dynamic>{
'transports': ['websocket', 'polling'],
});
socket.connect();
}
I can not connect it please help me.

I know this is an older question but hopefully this answer will help someone down the road.
The issue may be caused by the lack of support for polling in flutter.
from: https://github.com/rikulo/socket.io-client-dart#usage-flutter
In Flutter env. it only works with dart:io websocket, not with dart:html websocket, so in this case you have to add 'transports': ['websocket'] when creates the socket instance.
IO.Socket socket = IO.io('http://localhost:3000', <String, dynamic>{
'transports': ['websocket'],
'extraHeaders': {'foo': 'bar'} // optional
});
The default Flask development server doesn't support websockets so you'll need to use another server. Thankfully it's simple to get eventlet working with Flask. All you should have to do is install the eventlet package using pip.
pip install eventlet
Once eventlet is installed socketio will detect and use it when running the server.
You can use chrome to double check what transport method is being used. Open your chrome dev tools Ctrl+Shift+I in Windows and go to the Network tab. On each network request you should see either transport=polling or transport=websocket

Related

flask_socketio connected to client, but not receiving messages

I have a Flask server-app/React client-app into which I am trying to integrate flask_socketio. I have replicated the standard introductory example from the flask_socketio docs and it works fine with my React front-end.
However, when I try to replicate the results in flask, using the exact same steps I cannot send or receive messages. I can see a client has connected in the output when I run my flask app, and in the browser console I have a console.log telling me I am connected to the server, but emit (or send) don't seem to work the way the intro example did.
I have eventlet installed, and the docs say that flask_socketio should recognize this automatically. Here are some code snippets for reference.
app/socket/__ init __.py
from flask_socketio import SocketIO
socketio = SocketIO(cors_allowed_origins='http://localhost:3000')
app/socket/socket.py
from flask_cors import cross_origin
from flask_socketio import send, emit
from . import socketio
#cross_origin
#socketio.on('connect')
def handle_connection():
print('a user has connected')
emit('mymessage', 'Hi client, I am server.') # I've tried `send` here too
#cross_origin
#socketio.on('mymessage')
def handle_message(message):
print('Message from client: ' + message)
app/__ init __.py
from flask import Flask
from flask_cors import CORS
from .socket import socketio
def create_app():
app = Flask(__name__)
# Cross Origin Resource Sharing
CORS(app)
# Socket.IO
socketio.init_app(app)
return (socketio, app)
app/app.py
from . import create_app
socketio, app = create_app()
if __name__ == '__main__':
socketio.run(app, host='localhost', port=5000)
#app.run("0.0.0.0", port=5000, threaded=True, use_reloader=False)
React component
const socket = io('http://localhost:5000');
class Figures extends React.Component {
setSocketListeners () {
socket.on('connect', () => {
console.log('connected to socket');
socket.emit('mymessage', 'Hi server, I am client.');
})
socket.on('mymessage', function(data) {
console.log('Message from server: ' + data)
})
}
componentDidMount() {
this.setSocketListeners()
}
...
Output:
terminal
* Restarting with stat
* Debugger is active!
* Debugger PIN: 216-814-307
(4089) wsgi starting up on http://127.0.0.1:5000
127.0.0.1 - - [14/Aug/2019 02:40:35] "POST /socket.io/?EIO=3&transport=polling&t=MoEsrSZ&sid=a4f73c34553f478cabde2f919b48fe98 HTTP/1.1" 200 219 0.002675
(4089) accepted ('127.0.0.1', 36512)
(4089) accepted ('127.0.0.1', 36514)
127.0.0.1 - - [14/Aug/2019 02:40:36] "GET /socket.io/?EIO=3&transport=polling&t=MoEsrSf&sid=a4f73c34553f478cabde2f919b48fe98 HTTP/1.1" 200 235 1.612156
browser
connected to socket
EDIT:
Preliminary debugging seems to suggest this is some issue with 'create_app()'. See link from #miguelgrinberg. Still no progress on how to fix the issue though.
Have enabled socketio.init_app(app, async_mode="eventlet", engineio_logger=True) and disabled debugging in flask to make sure werkzeug isn't being used.
A similar issue was related here
I think you should enable transport mode to WebSocket when opening socket on your frontend code, something like:
const socket = io('http://localhost:5000', {transports: [websocket]});
Also you need to install gevent and gevent-websocket and import socket.io-client like:
import io from 'socket.io-client/dist/socket.io';
I've implemented a working example: https://github.com/roj4s/webicami

Python Twisted Authentication Without HTTP Authentication

I'm setting up a Flask server, and want to use a Twisted ReverseProxyResource to proxy over another local server. In Flask, I have a current_user.is_authenticated boolean which I use to protect pages. How can I lock the ReverseProxyResource using this variable, so that it cannot be accessed when a user is logged out? The twisted.web.guard module requires me to set up another HTTP authentication system entirely, and the library doesn't seem to have any other built-in solution.
I've set up some demo code, (based off a previous question) attempting to place the Flask server inside of the Twisted reactor. I'm using the ReverseProxyResource to allow for two-way communication with a Shellinabox server on port 4200.
from flask import Flask
from twisted.internet import reactor
from twisted.web.proxy import ReverseProxyResource
from twisted.web.resource import Resource
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
app = Flask(__name__)
#app.route('/example')
def index():
return 'Flask within Twisted?'
flask_site = WSGIResource(reactor, reactor.getThreadPool(), app)
root = Resource()
site_example = ReverseProxyResource('localhost', 4200, b'')
root.putChild(b'ssh', site_example)
reactor.listenTCP(8081, Site(root))
reactor.run()
I'd be okay switching to another reverse proxy, but only Twisted has worked so far. I'm also not wanting to switch to the Klein framework due to what I already have established in Flask.

Flask-SocketIO server using polling instead of websockets

I'm working on a Flask-SocketIO server that works just fine.
However, I'm getting lots of requests like this in my server log:
"GET /socket.io/?EIO=3&transport=polling&t=LBS1TQt HTTP/1.1"
Here's the code I'm working with:
from flask import Flask, render_template, redirect, url_for
from flask_socketio import SocketIO, emit
import json
def load_config():
# configuration
return json.load(open('/etc/geekdj/config.json'))
config = load_config()
geekdj = Flask(__name__)
geekdj.config["DEBUG"] = config["debug"]
geekdj.config["SECRET_KEY"] = config["secret_key"]
geekdj.config.from_envvar("FLASKR_SETTINGS", silent=True)
socketio = SocketIO(geekdj)
#geekdj.route('/')
def index():
return render_template('index.html')
# SocketIO functions
#socketio.on('connect')
def chat_connect():
print ('connected')
#socketio.on('disconnect')
def chat_disconnect():
print ("Client disconnected")
#socketio.on('broadcast')
def chat_broadcast(message):
print ("test")
emit("chat", {'data': message['data']})
if __name__ == "__main__":
socketio.run(geekdj, port=8000)
and the JS in index.html:
<script src="//cdn.socket.io/socket.io-1.4.5.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
// the socket.io documentation recommends sending an explicit package upon connection
// this is specially important when using the global namespace
var socket = io.connect('http://localhost:8000');
socket.on('connection', function(socket) {
socket.emit('foo', {foo: "bar"});
socket.join("test");
});
socket.on('joined', function(data) {
console.log('Joined room!');
console.log(data["room"]);
});
});
I'd prefer to be using actual Websockets if possible, does anyone know why SocketIO is falling back on polling?
Did the first answer work? If so, you should accept it. If not, post your requirements.txt please.
I had the same problem and found the resolution by fully absorbing the documentation page:
The asynchronous services that this package relies on can be selected
among three choices:
eventlet is the best performant option, with support for long-polling and WebSocket transports.
gevent is supported in a number of different configurations. The long-polling transport is fully supported with the gevent package,
but unlike eventlet, gevent does not have native WebSocket support.
To add support for WebSocket there are currently two options.
Installing the gevent-websocket package adds WebSocket support to
gevent or one can use the uWSGI web server, which comes with
WebSocket functionality. The use of gevent is also a performant
option, but slightly lower than eventlet.
The Flask development server based on Werkzeug can be used as well, with the caveat that it lacks the performance of the other two
options, so it should only be used to simplify the development
workflow. This option only supports the long-polling transport.
Basically, I didn't have evenlet nor gevent-websocket in my virtual environment. I installed eventlet, and transport upgrade to websocket was near instantaneous! Hope this helps.
I found the solution in this other Q/A.
It turns out that SocketIO sets a cookie with the most recent connection type that worked. In my case, it was polling.
So, I changed the SocketIO connect statement in my JS from
var socket = io.connect('http://localhost:8000');
to
var socket = io.connect(null, {port: 8000, rememberTransport: false});
and now there is activity in the websockets type under the Network tab in the Chrome developer tools (which there wasn't previously):

How to run WSGIServer in verbose or debug mode ?

I'm using the following code snippet to run WSGIServer in python:
from bottle import request, Bottle, abort
app = Bottle()
.. other stuff ...
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketError
from geventwebsocket.handler import WebSocketHandler
server = WSGIServer(("0.0.0.0", 8080), app,
handler_class=WebSocketHandler)
server.serve_forever()
The server works fine but every time I send a request to this server, there is nothing printed out on console (the way bottle or flask do when you run their server directly). Those console logs would really help me understand what requests the browser is making. I tried inserting debug=True in several places in above code, but none seemed to work. What am I doing wrong ?
I believe you should add this line before starting the server .
app.debug = True

Tornado web server in webfaction

I am starting with web development. I am trying to develop and webapp using the Instagram API and Django. I was looking that a lot of people it's using Tornado Web Server for Real Time Subscriptions. So I am using Webfaction as a host and found this code so I can wrap my Django project with the "WSGI Container" that Tornado Web Server provides:
import os
import tornado.httpserver
import tornado.ioloop
import tornado.wsgi
import tornado.web
import sys
import django.core.handlers.wsgi
sys.path.append('/path/to/project')
class HelloHandler(tornado.web.RequestHandler):
def get(self):
self.write('Hello from tornado')
def main():
os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings' # path to your settings module
wsgi_app = tornado.wsgi.WSGIContainer(django.core.handlers.wsgi.WSGIHandler())
tornado_app = tornado.web.Application(
[
('/hello-tornado', HelloHandler),
('.*', tornado.web.FallbackHandler, dict(fallback=wsgi_app)),
]
)
http_server = tornado.httpserver.HTTPServer(tornado_app)
http_server.listen(8080)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()
So I run this python script inside my Webfaction server and everytime I try to access "http://mywebsite.com/hello-tornado/" does not seem to work. I know I am running that Tornado web server on that port but do not know how too access from the browser or something like that. What I am doing wrong here? Thanks for your help and patience. Will cyber high-five for every answer.
EDIT: What I am really trying to do is that I want to receive all the calls from the subscriptions that I make with the Instagram RealTime Subscription API through Tornado, for that I have a callback url "http://mysite.com/sub" and I want to be able to receive through Tornado.
You are starting the server at port 8080, Web browsers use port 80 by default, try using: http://mywebsite.com:8080/hello-tornado
if you want to use port 80 and you already have a web server running in the box you can try following Ali-Akber Saifee suggestion, or run the WSGI application directly from the server, using something like mod_python (http://www.modpython.org), you will lose the ability to run Tornado code, but Django will work.
You have to create a custom app (listening on port), note the port that is assigned to your app then configure tornado to serve on that port: http_server.listen(my port)
You can also avoid tornado and start directly by installing a django app.

Categories

Resources