Skip to content

Commit

Permalink
Move to python-socketio 4.x and JS Socket.IO 3.x
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Dec 12, 2020
1 parent 7a83134 commit 0c674b8
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 70 deletions.
25 changes: 12 additions & 13 deletions example/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,30 @@ def background_thread():
socketio.sleep(10)
count += 1
socketio.emit('my_response',
{'data': 'Server generated event', 'count': count},
namespace='/test')
{'data': 'Server generated event', 'count': count})


@app.route('/')
def index():
return render_template('index.html', async_mode=socketio.async_mode)


@socketio.on('my_event', namespace='/test')
@socketio.on('my_event')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': message['data'], 'count': session['receive_count']})


@socketio.on('my_broadcast_event', namespace='/test')
@socketio.on('my_broadcast_event')
def test_broadcast_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': message['data'], 'count': session['receive_count']},
broadcast=True)


@socketio.on('join', namespace='/test')
@socketio.on('join')
def join(message):
join_room(message['room'])
session['receive_count'] = session.get('receive_count', 0) + 1
Expand All @@ -57,7 +56,7 @@ def join(message):
'count': session['receive_count']})


@socketio.on('leave', namespace='/test')
@socketio.on('leave')
def leave(message):
leave_room(message['room'])
session['receive_count'] = session.get('receive_count', 0) + 1
Expand All @@ -66,7 +65,7 @@ def leave(message):
'count': session['receive_count']})


@socketio.on('close_room', namespace='/test')
@socketio.on('close_room')
def close(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response', {'data': 'Room ' + message['room'] + ' is closing.',
Expand All @@ -75,15 +74,15 @@ def close(message):
close_room(message['room'])


@socketio.on('my_room_event', namespace='/test')
@socketio.on('my_room_event')
def send_room_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my_response',
{'data': message['data'], 'count': session['receive_count']},
room=message['room'])


@socketio.on('disconnect_request', namespace='/test')
@socketio.on('disconnect_request')
def disconnect_request():
@copy_current_request_context
def can_disconnect():
Expand All @@ -98,12 +97,12 @@ def can_disconnect():
callback=can_disconnect)


@socketio.on('my_ping', namespace='/test')
@socketio.on('my_ping')
def ping_pong():
emit('my_pong')


@socketio.on('connect', namespace='/test')
@socketio.on('connect')
def test_connect():
global thread
with thread_lock:
Expand All @@ -112,10 +111,10 @@ def test_connect():
emit('my_response', {'data': 'Connected', 'count': 0})


@socketio.on('disconnect', namespace='/test')
@socketio.on('disconnect')
def test_disconnect():
print('Client disconnected', request.sid)


if __name__ == '__main__':
socketio.run(app, debug=True)
socketio.run(app)
13 changes: 3 additions & 10 deletions example/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,14 @@
<html>
<head>
<title>Flask-SocketIO Test</title>
<script src="//code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script>
<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>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
// Use a "/test" namespace.
// An application can open a connection on multiple namespaces, and
// Socket.IO will multiplex all those connections on a single
// physical channel. If you don't care about multiple channels, you
// can set the namespace to an empty string.
namespace = '/test';

// Connect to the Socket.IO server.
// The connection URL has the following format, relative to the current page:
// http[s]://<domain>:<port>[/<namespace>]
var socket = io(namespace);
var socket = io();

// Event handler for new connections.
// The callback function is invoked when a connection with the
Expand Down
15 changes: 8 additions & 7 deletions flask_socketio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,18 +686,19 @@ def test_client(self, app, namespace=None, query_string=None,
flask_test_client=flask_test_client)

def _handle_event(self, handler, message, namespace, sid, *args):
if sid not in self.server.environ:
eio_sid = self.server.manager.eio_sid_from_sid(sid, namespace)
environ = self.server.get_environ(sid, namespace=namespace)
if not environ:
# we don't have record of this client, ignore this event
return '', 400
app = self.server.environ[sid]['flask.app']
with app.request_context(self.server.environ[sid]):
app = environ['flask.app']
with app.request_context(environ):
if self.manage_session:
# manage a separate session for this client's Socket.IO events
# created as a copy of the regular user session
if 'saved_session' not in self.server.environ[sid]:
self.server.environ[sid]['saved_session'] = \
_ManagedSession(flask.session)
session_obj = self.server.environ[sid]['saved_session']
if 'saved_session' not in environ:
environ['saved_session'] = _ManagedSession(flask.session)
session_obj = environ['saved_session']
else:
# let Flask handle the user session
# for cookie based sessions, this effectively freezes the
Expand Down
71 changes: 38 additions & 33 deletions flask_socketio/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,36 +28,38 @@ class SocketIOTestClient(object):

def __init__(self, app, socketio, namespace=None, query_string=None,
headers=None, flask_test_client=None):
def _mock_send_packet(sid, pkt):
def _mock_send_packet(eio_sid, pkt):
if pkt.packet_type == packet.EVENT or \
pkt.packet_type == packet.BINARY_EVENT:
if sid not in self.queue:
self.queue[sid] = []
if eio_sid not in self.queue:
self.queue[eio_sid] = []
if pkt.data[0] == 'message' or pkt.data[0] == 'json':
self.queue[sid].append({'name': pkt.data[0],
'args': pkt.data[1],
'namespace': pkt.namespace or '/'})
self.queue[eio_sid].append({
'name': pkt.data[0],
'args': pkt.data[1],
'namespace': pkt.namespace or '/'})
else:
self.queue[sid].append({'name': pkt.data[0],
'args': pkt.data[1:],
'namespace': pkt.namespace or '/'})
self.queue[eio_sid].append({
'name': pkt.data[0],
'args': pkt.data[1:],
'namespace': pkt.namespace or '/'})
elif pkt.packet_type == packet.ACK or \
pkt.packet_type == packet.BINARY_ACK:
self.acks[sid] = {'args': pkt.data,
'namespace': pkt.namespace or '/'}
elif pkt.packet_type in [packet.DISCONNECT, packet.ERROR]:
self.acks[eio_sid] = {'args': pkt.data,
'namespace': pkt.namespace or '/'}
elif pkt.packet_type in [packet.DISCONNECT, packet.CONNECT_ERROR]:
self.connected[pkt.namespace or '/'] = False

self.app = app
self.flask_test_client = flask_test_client
self.sid = uuid.uuid4().hex
self.queue[self.sid] = []
self.acks[self.sid] = None
self.eio_sid = uuid.uuid4().hex
self.acks[self.eio_sid] = None
self.queue[self.eio_sid] = []
self.callback_counter = 0
self.socketio = socketio
self.connected = {}
socketio.server._send_packet = _mock_send_packet
socketio.server.environ[self.sid] = {}
socketio.server.environ[self.eio_sid] = {}
socketio.server.async_handlers = False # easier to test when
socketio.server.eio.async_handlers = False # events are sync
if isinstance(socketio.server.manager, PubSubManager):
Expand Down Expand Up @@ -91,6 +93,7 @@ def connect(self, namespace=None, query_string=None, headers=None):
is when the application accepts multiple namespace connections.
"""
url = '/socket.io'
namespace = namespace or '/'
if query_string:
if query_string[0] != '?':
query_string = '?' + query_string
Expand All @@ -100,16 +103,15 @@ def connect(self, namespace=None, query_string=None, headers=None):
if self.flask_test_client:
# inject cookies from Flask
self.flask_test_client.cookie_jar.inject_wsgi(environ)
ret = self.socketio.server._handle_eio_connect(self.sid, environ)
if ret is None or ret is True:
self.connected['/'] = True
if namespace is not None and namespace != '/':
pkt = packet.Packet(packet.CONNECT, namespace=namespace)
with self.app.app_context():
ret = self.socketio.server._handle_eio_message(self.sid,
pkt.encode())
if ret is None or ret is True:
self.connected[namespace] = True
self.socketio.server._handle_eio_connect(self.eio_sid, environ)
pkt = packet.Packet(packet.CONNECT, namespace=namespace)
with self.app.app_context():
ret = self.socketio.server._handle_eio_message(self.eio_sid,
pkt.encode())
sid = self.socketio.server.manager.sid_from_eio_sid(self.eio_sid,
namespace)
if sid:
self.connected[namespace] = True

def disconnect(self, namespace=None):
"""Disconnect the client.
Expand All @@ -121,7 +123,8 @@ def disconnect(self, namespace=None):
raise RuntimeError('not connected')
pkt = packet.Packet(packet.DISCONNECT, namespace=namespace)
with self.app.app_context():
self.socketio.server._handle_eio_message(self.sid, pkt.encode())
self.socketio.server._handle_eio_message(self.eio_sid,
pkt.encode())
del self.connected[namespace or '/']

def emit(self, event, *args, **kwargs):
Expand Down Expand Up @@ -153,10 +156,12 @@ def emit(self, event, *args, **kwargs):
encoded_pkt = pkt.encode()
if isinstance(encoded_pkt, list):
for epkt in encoded_pkt:
self.socketio.server._handle_eio_message(self.sid, epkt)
self.socketio.server._handle_eio_message(self.eio_sid,
epkt)
else:
self.socketio.server._handle_eio_message(self.sid, encoded_pkt)
ack = self.acks.pop(self.sid, None)
self.socketio.server._handle_eio_message(self.eio_sid,
encoded_pkt)
ack = self.acks.pop(self.eio_sid, None)
if ack is not None:
return ack['args'][0] if len(ack['args']) == 1 \
else ack['args']
Expand Down Expand Up @@ -197,8 +202,8 @@ def get_received(self, namespace=None):
if not self.is_connected(namespace):
raise RuntimeError('not connected')
namespace = namespace or '/'
r = [pkt for pkt in self.queue[self.sid]
r = [pkt for pkt in self.queue[self.eio_sid]
if pkt['namespace'] == namespace]
self.queue[self.sid] = [pkt for pkt in self.queue[self.sid]
if pkt not in r]
self.queue[self.eio_sid] = [
pkt for pkt in self.queue[self.eio_sid] if pkt not in r]
return r
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
platforms='any',
install_requires=[
'Flask>=0.9',
'python-socketio>=4.3.0,<5'
'python-socketio>=5.0.2'
],
tests_require=[
'coverage'
Expand All @@ -38,7 +38,6 @@
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
'Topic :: Software Development :: Libraries :: Python Modules'
Expand Down
12 changes: 7 additions & 5 deletions test_socketio.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def test_connect(self):
client2 = socketio.test_client(app)
self.assertTrue(client.is_connected())
self.assertTrue(client2.is_connected())
self.assertNotEqual(client.sid, client2.sid)
self.assertNotEqual(client.eio_sid, client2.eio_sid)
received = client.get_received()
self.assertEqual(len(received), 3)
self.assertEqual(received[0]['args'], 'connected')
Expand Down Expand Up @@ -443,11 +443,13 @@ def test_session(self):
client = socketio.test_client(app, flask_test_client=flask_client)
client.get_received()
client.send('echo this message back')
self.assertEqual(socketio.server.environ[client.sid]['saved_session'],
{'foo': 'bar'})
self.assertEqual(
socketio.server.environ[client.eio_sid]['saved_session'],
{'foo': 'bar'})
client.send('test session')
self.assertEqual(socketio.server.environ[client.sid]['saved_session'],
{'a': 'b', 'foo': 'bar'})
self.assertEqual(
socketio.server.environ[client.eio_sid]['saved_session'],
{'a': 'b', 'foo': 'bar'})

def test_room(self):
client1 = socketio.test_client(app)
Expand Down

0 comments on commit 0c674b8

Please sign in to comment.