6 changed files with 324 additions and 1 deletions
@ -0,0 +1,96 @@ |
|||||
|
class Namespace(object): |
||||
|
"""Base class for class-based namespaces. |
||||
|
|
||||
|
A class-based namespace is a class that contains all the event handlers |
||||
|
for a Socket.IO namespace. The event handlers are methods of the class |
||||
|
with the prefix ``on_``, such as ``on_connect``, ``on_disconnect``, |
||||
|
``on_message``, ``on_json``, and so on. |
||||
|
|
||||
|
:param namespace: The Socket.IO namespace to be used with all the event |
||||
|
handlers defined in this class. If this argument is |
||||
|
omitted, the default namespace is used. |
||||
|
""" |
||||
|
def __init__(self, namespace=None): |
||||
|
self.namespace = namespace or '/' |
||||
|
self.server = None |
||||
|
|
||||
|
def set_server(self, server): |
||||
|
self.server = server |
||||
|
|
||||
|
def trigger_event(self, event, *args): |
||||
|
handler_name = 'on_' + event |
||||
|
if hasattr(self, handler_name): |
||||
|
return getattr(self, handler_name)(*args) |
||||
|
|
||||
|
def emit(self, event, data=None, room=None, skip_sid=None, namespace=None, |
||||
|
callback=None): |
||||
|
"""Emit a custom event to one or more connected clients. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.emit` method is |
||||
|
that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
""" |
||||
|
return self.server.emit(event, data=data, room=room, skip_sid=skip_sid, |
||||
|
namespace=namespace or self.namespace, |
||||
|
callback=callback) |
||||
|
|
||||
|
def send(self, data, room=None, skip_sid=None, namespace=None, |
||||
|
callback=None): |
||||
|
"""Send a message to one or more connected clients. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.send` method is |
||||
|
that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
""" |
||||
|
return self.server.send(data, room=room, skip_sid=skip_sid, |
||||
|
namespace=namespace or self.namespace, |
||||
|
callback=callback) |
||||
|
|
||||
|
def enter_room(self, sid, room, namespace=None): |
||||
|
"""Enter a room. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.enter_room` method |
||||
|
is that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
""" |
||||
|
return self.server.enter_room(sid, room, |
||||
|
namespace=namespace or self.namespace) |
||||
|
|
||||
|
def leave_room(self, sid, room, namespace=None): |
||||
|
"""Leave a room. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.leave_room` method |
||||
|
is that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
""" |
||||
|
return self.server.leave_room(sid, room, |
||||
|
namespace=namespace or self.namespace) |
||||
|
|
||||
|
def close_room(self, room, namespace=None): |
||||
|
"""Close a room. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.close_room` method |
||||
|
is that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
""" |
||||
|
return self.server.close_room(room, |
||||
|
namespace=namespace or self.namespace) |
||||
|
|
||||
|
def rooms(self, sid, namespace=None): |
||||
|
"""Return the rooms a client is in. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.rooms` method is |
||||
|
that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
""" |
||||
|
return self.server.rooms(sid, namespace=namespace or self.namespace) |
||||
|
|
||||
|
def disconnect(self, sid, namespace=None): |
||||
|
"""Disconnect a client. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.disconnect` method |
||||
|
is that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
""" |
||||
|
return self.server.disconnect(sid, |
||||
|
namespace=namespace or self.namespace) |
@ -0,0 +1,129 @@ |
|||||
|
import unittest |
||||
|
import six |
||||
|
if six.PY3: |
||||
|
from unittest import mock |
||||
|
else: |
||||
|
import mock |
||||
|
|
||||
|
from socketio import namespace |
||||
|
|
||||
|
|
||||
|
class TestNamespace(unittest.TestCase): |
||||
|
def test_connect_event(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(namespace.Namespace): |
||||
|
def on_connect(self, sid, environ): |
||||
|
result['result'] = (sid, environ) |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.trigger_event('connect', 'sid', {'foo': 'bar'}) |
||||
|
self.assertEqual(result['result'], ('sid', {'foo': 'bar'})) |
||||
|
|
||||
|
def test_disconnect_event(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(namespace.Namespace): |
||||
|
def on_disconnect(self, sid): |
||||
|
result['result'] = sid |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.trigger_event('disconnect', 'sid') |
||||
|
self.assertEqual(result['result'], 'sid') |
||||
|
|
||||
|
def test_event(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(namespace.Namespace): |
||||
|
def on_custom_message(self, sid, data): |
||||
|
result['result'] = (sid, data) |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.trigger_event('custom_message', 'sid', {'data': 'data'}) |
||||
|
self.assertEqual(result['result'], ('sid', {'data': 'data'})) |
||||
|
|
||||
|
def test_event_not_found(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(namespace.Namespace): |
||||
|
def on_custom_message(self, sid, data): |
||||
|
result['result'] = (sid, data) |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.trigger_event('another_custom_message', 'sid', {'data': 'data'}) |
||||
|
self.assertEqual(result, {}) |
||||
|
|
||||
|
def test_emit(self): |
||||
|
ns = namespace.Namespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.emit('ev', data='data', room='room', skip_sid='skip', |
||||
|
callback='cb') |
||||
|
ns.server.emit.assert_called_with( |
||||
|
'ev', data='data', room='room', skip_sid='skip', namespace='/foo', |
||||
|
callback='cb') |
||||
|
ns.emit('ev', data='data', room='room', skip_sid='skip', |
||||
|
namespace='/bar', callback='cb') |
||||
|
ns.server.emit.assert_called_with( |
||||
|
'ev', data='data', room='room', skip_sid='skip', namespace='/bar', |
||||
|
callback='cb') |
||||
|
|
||||
|
def test_send(self): |
||||
|
ns = namespace.Namespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.send(data='data', room='room', skip_sid='skip', callback='cb') |
||||
|
ns.server.send.assert_called_with( |
||||
|
'data', room='room', skip_sid='skip', namespace='/foo', |
||||
|
callback='cb') |
||||
|
ns.send(data='data', room='room', skip_sid='skip', namespace='/bar', |
||||
|
callback='cb') |
||||
|
ns.server.send.assert_called_with( |
||||
|
'data', room='room', skip_sid='skip', namespace='/bar', |
||||
|
callback='cb') |
||||
|
|
||||
|
def test_enter_room(self): |
||||
|
ns = namespace.Namespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.enter_room('sid', 'room') |
||||
|
ns.server.enter_room.assert_called_with('sid', 'room', |
||||
|
namespace='/foo') |
||||
|
ns.enter_room('sid', 'room', namespace='/bar') |
||||
|
ns.server.enter_room.assert_called_with('sid', 'room', |
||||
|
namespace='/bar') |
||||
|
|
||||
|
def test_leave_room(self): |
||||
|
ns = namespace.Namespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.leave_room('sid', 'room') |
||||
|
ns.server.leave_room.assert_called_with('sid', 'room', |
||||
|
namespace='/foo') |
||||
|
ns.leave_room('sid', 'room', namespace='/bar') |
||||
|
ns.server.leave_room.assert_called_with('sid', 'room', |
||||
|
namespace='/bar') |
||||
|
|
||||
|
def test_close_room(self): |
||||
|
ns = namespace.Namespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.close_room('room') |
||||
|
ns.server.close_room.assert_called_with('room', namespace='/foo') |
||||
|
ns.close_room('room', namespace='/bar') |
||||
|
ns.server.close_room.assert_called_with('room', namespace='/bar') |
||||
|
|
||||
|
def test_rooms(self): |
||||
|
ns = namespace.Namespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.rooms('sid') |
||||
|
ns.server.rooms.assert_called_with('sid', namespace='/foo') |
||||
|
ns.rooms('sid', namespace='/bar') |
||||
|
ns.server.rooms.assert_called_with('sid', namespace='/bar') |
||||
|
|
||||
|
def test_disconnect(self): |
||||
|
ns = namespace.Namespace('/foo') |
||||
|
ns.set_server(mock.MagicMock()) |
||||
|
ns.disconnect('sid') |
||||
|
ns.server.disconnect.assert_called_with('sid', namespace='/foo') |
||||
|
ns.disconnect('sid', namespace='/bar') |
||||
|
ns.server.disconnect.assert_called_with('sid', namespace='/bar') |
Loading…
Reference in new issue