Skip to content

Commit

Permalink
various minor improvements for asyncio support
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Feb 11, 2017
1 parent f86847b commit 24131a9
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 11 deletions.
4 changes: 2 additions & 2 deletions engineio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

__version__ = '1.2.0'

__all__ = [__version__, Middleware, Server]
__all__ = ['__version__', 'Middleware', 'Server']
if AsyncServer is not None: # pragma: no cover
__all__.append(AsyncServer)
__all__.append('AsyncServer')
41 changes: 34 additions & 7 deletions engineio/asyncio_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def async_modes(self):
return ['aiohttp']

def attach(self, app, engineio_path='engine.io'):
"""Attach the Engine.IO server to an application."""
self._async['create_route'](app, self, '/{}/'.format(engineio_path))

async def send(self, sid, data, binary=None):
Expand All @@ -67,6 +68,8 @@ async def send(self, sid, data, binary=None):
as text. If not given, unicode (Python 2) and str
(Python 3) are sent as text, and str (Python 2) and
bytes (Python 3) are sent as binary.
Note: this method is a coroutine.
"""
try:
socket = self._get_socket(sid)
Expand All @@ -82,21 +85,24 @@ async def disconnect(self, sid=None):
:param sid: The session id of the client to close. If this parameter
is not given, then all clients are closed.
Note: this method is a coroutine.
"""
if sid is not None:
await self._get_socket(sid).close()
del self.sockets[sid]
else:
for client in six.itervalues(self.sockets):
await client.close()
await asyncio.wait([client.close()
for client in six.itervalues(self.sockets)])
self.sockets = {}

async def handle_request(self, *args, **kwargs):
"""Handle an HTTP request from the client.
This is the entry point of the Engine.IO application.
This is the entry point of the Engine.IO application. This function
returns the HTTP response to deliver to the client.
This function returns the HTTP response to deliver to the client.
Note: this method is a coroutine.
"""
environ = self._async['translate_request'](*args, **kwargs)
method = environ['REQUEST_METHOD']
Expand Down Expand Up @@ -169,10 +175,31 @@ async def handle_request(self, *args, **kwargs):
r['response'])

def start_background_task(self, target, *args, **kwargs):
raise RuntimeError('Not implemented, use asyncio.')
"""Start a background task using the appropriate async model.
This is a utility function that applications can use to start a
background task using the method that is compatible with the
selected async mode.
def sleep(self, seconds=0):
raise RuntimeError('Not implemented, use asyncio.')
:param target: the target function to execute.
:param args: arguments to pass to the function.
:param kwargs: keyword arguments to pass to the function.
The return value is a ``asyncio.Task`` object.
"""
return asyncio.ensure_future(target(*args, **kwargs))

async def sleep(self, seconds=0):
"""Sleep for the requested amount of time using the appropriate async
model.
This is a utility function that applications can use to put a task to
sleep without having to worry about using the correct call for the
selected async mode.
Note: this method is a coroutine.
"""
return await asyncio.sleep(seconds)

async def _handle_connect(self, environ, transport, b64=False):
"""Handle a client connection request."""
Expand Down
13 changes: 11 additions & 2 deletions tests/test_asyncio_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,12 +669,21 @@ def loads(*args, **kwargs):
packet.Packet.json = json

def test_background_tasks(self):
r = []

@coroutine
def foo(arg):
r.append(arg)

s = asyncio_server.AsyncServer()
self.assertRaises(RuntimeError, s.start_background_task, 'foo')
s.start_background_task(foo, 'bar')
pending = asyncio.Task.all_tasks()
asyncio.get_event_loop().run_until_complete(asyncio.wait(pending))
self.assertEqual(r, ['bar'])

def test_sleep(self):
s = asyncio_server.AsyncServer()
self.assertRaises(RuntimeError, s.sleep)
_run(s.sleep(0))

def test_trigger_event_function(self):
result = []
Expand Down

0 comments on commit 24131a9

Please sign in to comment.