I'm trying to understand how sessions work in flask_session extension. I have server-side code:
from flask import Flask, session
from flask_session import Session
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'top-secret!'
app.config['SESSION_TYPE'] = 'filesystem'
Session(app)
socketio = SocketIO(app, manage_session=False)
#socketio.on('get-session')
def get_session():
print(session.get('value', 'NO'))
#socketio.on('set-session')
def set_session(data):
session['value'] = data
print(session.get('value', 'NO'))
if __name__ == '__main__':
socketio.run(app)
and client:
from socketIO_client import SocketIO
with SocketIO('localhost', 5000) as socketio:
socketio.emit('set-session', '3')
socketio.emit('get-session')
I get following output on server:
3
NO
But i want to get:
3
3
I can't understand why session variable is not preserved. Would appreciate any help.
UPD: execution of the above code results in two different files in \flask_session directory
Related
I built a very simple flask app that uses socketIo in order to make a simple chatapp, where you can write messages.
In my js file i built a function that every few seconds sends the current location of the user using geolocation.
Because im using the geolocation, i need my to use https instead of http that the flask created.
I found out about SSLify and tried it, but because im using also the socketIo it ran on http and not on https. In apps without socketIo it works, what is the problem?
this is my flask app:
from flask import Flask, render_template
from flask_socketio import SocketIO
from flask_sslify import SSLify
app = Flask(__name__)
app.config['SECRET_KEY'] = 'jsbcfsbfjefebw237u3gdbdc'
socketio = SocketIO(app)
sslify = SSLify(app)
#app.route('/')
def index():
return render_template('./ChatApp.html')
def messageRecived():
print('message was received!!!')
#socketio.on('my event')
def handle_my_custom_event(json):
print('recived my event: ' + str(json))
socketio.emit('my response', json, callback=messageRecived)
if __name__ == '__main__':
socketio.run(app, debug=True, host='0.0.0.0')
The reason it does not work is that Flask-SSLify is applied to your Flask application (the app instance), and not to Socket.IO (the socketio instance).
To my knowledge there is no equivalent to Flask-SSLify for the Socket.IO server, so you will need to either build it yourself as a WSGI middleware, or else implement the HTTP to HTTPS redirection in a reverse proxy that sits above your Python server, such as nginx or Apache.
I'm running this very simple application.py file, in debug mode, on my Mac.
import os
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config["SECRET_KEY"] = "secret"
socketio = SocketIO(app)
#app.route("/")
def index():
return "hello"
if __name__ == '__main__':
socketio.run(app, debug=True)
It shows up on 127.0.0.1:5000. When I change return "hello" to return "goodbye" and refresh the page, nothing happens. When I try to return render_template(goodbye.html) from my templates directory, nothing happens. I even changed the route from '/' to '/bbbb' and nothing changed. I see a bunch of GET requests in my terminal, each with a status code of 200.
I've never had this problem with Flask, that is until I tried to use sockets.io. Any thoughts on what is happening?
I am using Eventlet to do some background emit processes, but now ever since starting to use Eventlet, under every handler under #socketio.on, the request variable does not work as intended. For example, under an ordinary #APP.route('/abc/') I can use request.cookies.get('csrf'), etc. But under #socketio.on, request simply isn't the same. request.cookies.get('...') returns None every time.
import json
import os
import time
import eventlet
import gamble
import eng_puzzle
import authentication
import gcaptchacheck
from flask import Flask, redirect, url_for, request, render_template, make_response
from flask_compress import Compress
from flask_socketio import SocketIO, send, emit
from flask_sslify import SSLify
from store import REDISDB
eventlet.monkey_patch()
These are the imports.
def bg_emit():
"""Background emit"""
currentpotinfo = json.loads(REDISDB.get('potinfo').decode('UTF-8'))
pot_info = {
'id': currentpotinfo['id'],
'endtime': currentpotinfo['starttime'] + 30 - int(time.time()),
'hashwin': currentpotinfo['hashwin'],
'message': 'Entries closing in: ',
'winner': 'Not yet chosen'
}
socketio.emit('infoupdate', {'info': pot_info}, broadcast=True)
Background emit function (above)
def testemit():
"""test"""
while True:
bg_emit()
eventlet.sleep(1)
How it is called (above)
APP = Flask(__name__)
Compress(APP)
socketio = SocketIO(APP)
Defining APP and socketio (above)
if __name__ == '__main__':
print('RUN')
eventlet.spawn(testemit)
try:
socketio.run(APP, port=80, debug=True)
except PermissionError:
HPORT = int(os.environ.get('PORT'))
socketio.run(APP, port=HPORT, debug=False)
How the server is run. The except is just for deployment. (above)
#socketio.on('pot')
def handle_message(message):
"""Handle messages"""
print(message)
user = authentication.checksession(request)
print('user', user)
print(request.cookies.get('csrf'))
if user and request.cookies.get('csrf') == message.get('csrf'):
One of the places that are having trouble. authentication is a custom script for authentication site wide. There are debug messages and they prove that None is returned every time a cookie is called. How can I get around this issue? Is there a solve to the issue itself or do I have to make my own way around it?
When I run my local application with flask-socketio I can access session using from flask import session, but when I run it with gunicorn on server (gunicorn --worker-class eventlet -w 1 app:app) it return me session.keys() as Array[0].
How could I fix it to establish this local-proxy with session on server?
Thanks
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#app.before_request
def before_request():
session['key_1'] = 'Hello,'
session['key_2'] = 'World'
#app.route('/')
def index():
return render_template('index.html')
#socketio.on('connect', namespace='/')
def socket_connect():
session_keys = session.keys()
emit('connect response', {
'session_keys': session_keys
})
#socketio.on('disconnect', namespace='/')
def socket_disconnect():
print('Client disconnected', request.sid)
if __name__ == '__main__':
socketio.run(app)
I found a solution.
Session was dissapearing and could not be shared to socketio, because I added redirect page rules on cloudflare for my domain.
When I changed Forwarding type of all rules to 302 - Temporary everything worked well.
I've been trying to send data from flask over socket io. I need to access this data from a different origin, but it is giving a CORS error. I have tried using all kinds of cross origin stuff and none of it has worked. Can somebody help with this.
The view that should be called thought socket io:
from flask.ext.cors import cross_origin
#socketio.on('increment',namespace="/api")
#cross_origin()
def increment(message):
number += 1;
emit('number',{'data':number},broadcast=True)
Running the server:
app = Flask(__name__)
cors = CORS(app,resources={r"/api/*":{"origins":"*"}})
socketio = SocketIO(app)
app.debug = True
app.host = '0.0.0.0'
socketio.run(app)
I solved by following:
socketio = SocketIO(app, cors_allowed_origins="*")
For some reason, cors_allowed_origins="*" did not work for me. I had to instead specify the full address of the origin as the following:
socketio = SocketIO(app, cors_allowed_origins=['http://127.0.0.1:5500'])
The error message that says "<client_address> is not an accepted origin. (further occurrences of this error will be logged with level info)" should indicate which address you should be typing in.
I had a similar issue, got it working with this setup:
#you may not need all these options
from flask import Flask, render_template, request
from flask.ext.socketio import SocketIO, emit, join_room, leave_room
from flask.ext.cors import CORS
app = Flask(__name__, template_folder='./', static_folder='./', static_url_path='')
app.config['SECRET_KEY'] = 'some-super-secret-key'
app.config['DEFAULT_PARSERS'] = [
'flask.ext.api.parsers.JSONParser',
'flask.ext.api.parsers.URLEncodedParser',
'flask.ext.api.parsers.FormParser',
'flask.ext.api.parsers.MultiPartParser'
]
cors = CORS(app,resources={r"/*":{"origins":"*"}})
socketio = SocketIO(app)
socketio.run(app,port=5000,host='0.0.0.0')
You can set up routes as such:
#app.route("/")
def indexRoute():
return render_template('index.html',version=VER)
And socket requests:
#socketio.on('connect',namespace="/home")
def test_connect():
print "client connected:",rooms()[0]
On the client side in JS i did the following:
var socket = io.connect('http://' + location.hostname + ':5000/home');
socket.on('connect',function(data) {
console.log('connected to socket');
});
Also, take a look at this snippet from Flask developers.
Check that you are using the supported version of socket.io in your html file.
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js" integrity="sha512-aMGMvNYu8Ue4G+fHa359jcPb1u+ytAF+P2SCb+PxrjCdO3n3ZTxJ30zuH39rimUggmTwmh2u7wvQsDTHESnmfQ==" crossorigin="anonymous"></script>