Skip to content

Commit

Permalink
migrate to ASGI3 (#108)
Browse files Browse the repository at this point in the history
  • Loading branch information
florimondmanca authored and miguelgrinberg committed Apr 28, 2019
1 parent 88400ba commit 5a7f9e7
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 49 deletions.
64 changes: 30 additions & 34 deletions engineio/async_drivers/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,54 +40,50 @@ def __init__(self, engineio_server, other_asgi_app=None,
self.engineio_path = engineio_path.strip('/')
self.static_files = static_files or {}

def __call__(self, scope):
async def __call__(self, scope, receive, send):
if scope['type'] in ['http', 'websocket'] and \
scope['path'].startswith('/{0}/'.format(self.engineio_path)):
return self.engineio_asgi_app(scope)
await self.engineio_asgi_app(scope, receive, send)
elif scope['type'] == 'http' and scope['path'] in self.static_files:
return self.serve_static_file(scope)
await self.serve_static_file(scope, receive, send)
elif self.other_asgi_app is not None:
return self.other_asgi_app(scope)
await self.other_asgi_app(scope, receive, send)
elif scope['type'] == 'lifespan':
return self.lifespan
await self.lifespan(scope, receive, send)
else:
return self.not_found
await self.not_found(scope, receive, send)

def engineio_asgi_app(self, scope):
async def _app(receive, send):
await self.engineio_server.handle_request(scope, receive, send)
return _app
async def engineio_asgi_app(self, scope, receive, send):
await self.engineio_server.handle_request(scope, receive, send)

def serve_static_file(self, scope):
async def _send_static_file(receive, send): # pragma: no cover
event = await receive()
if event['type'] == 'http.request':
if scope['path'] in self.static_files:
content_type = self.static_files[scope['path']][
'content_type'].encode('utf-8')
filename = self.static_files[scope['path']]['filename']
status_code = 200
with open(filename, 'rb') as f:
payload = f.read()
else:
content_type = b'text/plain'
status_code = 404
payload = b'not found'
await send({'type': 'http.response.start',
'status': status_code,
'headers': [(b'Content-Type', content_type)]})
await send({'type': 'http.response.body',
'body': payload})
return _send_static_file

async def lifespan(self, receive, send):
async def serve_static_file(self, scope, receive, send):
event = await receive()
if event['type'] == 'http.request':
if scope['path'] in self.static_files:
content_type = self.static_files[scope['path']][
'content_type'].encode('utf-8')
filename = self.static_files[scope['path']]['filename']
status_code = 200
with open(filename, 'rb') as f:
payload = f.read()
else:
content_type = b'text/plain'
status_code = 404
payload = b'not found'
await send({'type': 'http.response.start',
'status': status_code,
'headers': [(b'Content-Type', content_type)]})
await send({'type': 'http.response.body',
'body': payload})

async def lifespan(self, scope, receive, send):
event = await receive()
if event['type'] == 'lifespan.startup':
await send({'type': 'lifespan.startup.complete'})
elif event['type'] == 'lifespan.shutdown':
await send({'type': 'lifespan.shutdown.complete'})

async def not_found(self, receive, send):
async def not_found(self, scope, receive, send):
"""Return a 404 Not Found error to the client."""
await send({'type': 'http.response.start',
'status': 404,
Expand Down
29 changes: 14 additions & 15 deletions tests/asyncio/test_async_asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,63 +45,62 @@ def test_engineio_routing(self):
mock_server.handle_request = AsyncMock()
app = async_asgi.ASGIApp(mock_server)
scope = {'type': 'http', 'path': '/engine.io/'}
handler = app(scope)
_run(handler('receive', 'send'))
_run(app(scope, 'receive', 'send'))
mock_server.handle_request.mock.assert_called_once_with(
scope, 'receive', 'send')

def test_other_app_routing(self):
other_app = mock.MagicMock()
other_app = AsyncMock()
app = async_asgi.ASGIApp('eio', other_app)
scope = {'type': 'http', 'path': '/foo'}
app(scope)
other_app.assert_called_once_with(scope)
_run(app(scope, 'receive', 'send'))
other_app.mock.assert_called_once_with(scope, 'receive', 'send')

def test_static_file_routing(self):
root_dir = os.path.dirname(__file__)
app = async_asgi.ASGIApp('eio', static_files={
'/foo': {'content_type': 'text/html',
'filename': root_dir + '/index.html'}
})
handler = app({'type': 'http', 'path': '/foo'})
scope = {'type': 'http', 'path': '/foo'}
receive = AsyncMock(return_value={'type': 'http.request'})
send = AsyncMock()
_run(handler(receive, send))
_run(app(scope, receive, send))
send.mock.assert_called_with({'type': 'http.response.body',
'body': b'<html></html>\n'})

def test_lifespan_startup(self):
app = async_asgi.ASGIApp('eio')
handler = app({'type': 'lifespan'})
scope = {'type': 'lifespan'}
receive = AsyncMock(return_value={'type': 'lifespan.startup'})
send = AsyncMock()
_run(handler(receive, send))
_run(app(scope, receive, send))
send.mock.assert_called_once_with(
{'type': 'lifespan.startup.complete'})

def test_lifespan_shutdown(self):
app = async_asgi.ASGIApp('eio')
handler = app({'type': 'lifespan'})
scope = {'type': 'lifespan'}
receive = AsyncMock(return_value={'type': 'lifespan.shutdown'})
send = AsyncMock()
_run(handler(receive, send))
_run(app(scope, receive, send))
send.mock.assert_called_once_with(
{'type': 'lifespan.shutdown.complete'})

def test_lifespan_invalid(self):
app = async_asgi.ASGIApp('eio')
handler = app({'type': 'lifespan'})
scope = {'type': 'lifespan'}
receive = AsyncMock(return_value={'type': 'lifespan.foo'})
send = AsyncMock()
_run(handler(receive, send))
_run(app(scope, receive, send))
send.mock.assert_not_called()

def test_not_found(self):
app = async_asgi.ASGIApp('eio')
handler = app({'type': 'http', 'path': '/foo'})
scope = {'type': 'http', 'path': '/foo'}
receive = AsyncMock(return_value={'type': 'http.request'})
send = AsyncMock()
_run(handler(receive, send))
_run(app(scope, receive, send))
send.mock.assert_any_call(
{'type': 'http.response.start', 'status': 404,
'headers': [(b'Content-Type', b'text/plain')]})
Expand Down

0 comments on commit 5a7f9e7

Please sign in to comment.