# Buggy code
async def asgi_send(self, message):
    message_type = message["type"]

    if not self.handshake_started_event.is_set():
        if message_type == "websocket.accept":
            self.logger.info(
                '%s - "WebSocket %s" [accepted]',
                self.scope["client"],
                self.scope["root_path"] + self.scope["path"],
            )
            self.initial_response = None
            self.accepted_subprotocol = message.get("subprotocol")
            self.handshake_started_event.set()

        elif message_type == "websocket.close":
            self.logger.info(
                '%s - "WebSocket %s" 403',
                self.scope["client"],
                self.scope["root_path"] + self.scope["path"],
            )
            self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b"")
            self.handshake_started_event.set()
            self.closed_event.set()

        else:
            msg = (
                "Expected ASGI message 'websocket.accept' or 'websocket.close', "
                "but got '%s'."
            )
            raise RuntimeError(msg % message_type)

    elif not self.closed_event.is_set():
        await self.handshake_completed_event.wait()

        if message_type == "websocket.send":
            bytes_data = message.get("bytes")
            text_data = message.get("text")
            data = text_data if bytes_data is None else bytes_data
            await self.send(data)

        elif message_type == "websocket.close":
            code = message.get("code", 1000)
            self.close_code = code  # for WebSocketServerProtocol
            await self.close(code)
            self.closed_event.set()

        else:
            msg = (
                "Expected ASGI message 'websocket.send' or 'websocket.close',"
                " but got '%s'."
            )
            raise RuntimeError(msg % message_type)

    else:
        msg = "Unexpected ASGI message '%s', after sending 'websocket.close'."
        raise RuntimeError(msg % message_type)


# Traceback (TypeError)
Traceback (most recent call last):
File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 140, in run_asgi
result = await asgi(self.asgi_receive, self.asgi_send)
File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/sessions.py", line 179, in __call__
return await self.inner(receive, self.send)
File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/middleware.py", line 41, in coroutine_call
await inner_instance(receive, send)
File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/consumer.py", line 59, in __call__
[receive, self.channel_receive], self.dispatch
File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/utils.py", line 59, in await_many_dispatch
await task
File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/utils.py", line 51, in await_many_dispatch
result = task.result()
File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 222, in asgi_receive
data = await self.recv()
File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/websockets/protocol.py", line 419, in recv
return_when=asyncio.FIRST_COMPLETED,
File "/usr/lib/python3.7/asyncio/tasks.py", line 361, in wait
fs = {ensure_future(f, loop=loop) for f in set(fs)}
File "/usr/lib/python3.7/asyncio/tasks.py", line 361, in <setcomp>
fs = {ensure_future(f, loop=loop) for f in set(fs)}
File "/usr/lib/python3.7/asyncio/tasks.py", line 592, in ensure_future
raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitable is required

# Fixed code
async def asgi_send(self, message):
    message_type = message["type"]

    if not self.handshake_started_event.is_set():
        if message_type == "websocket.accept":
            self.logger.info(
                '%s - "WebSocket %s" [accepted]',
                self.scope["client"],
                self.scope["root_path"] + self.scope["path"],
            )
            self.initial_response = None
            self.accepted_subprotocol = message.get("subprotocol")
            self.handshake_started_event.set()

        elif message_type == "websocket.close":
            self.logger.info(
                '%s - "WebSocket %s" 403',
                self.scope["client"],
                self.scope["root_path"] + self.scope["path"],
            )
            self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b"")
            self.handshake_started_event.set()
            self.closed_event.set()

        else:
            msg = (
                "Expected ASGI message 'websocket.accept' or 'websocket.close', "
                "but got '%s'."
            )
            raise RuntimeError(msg % message_type)

    elif not self.closed_event.is_set():
        await self.handshake_completed_event.wait()

        if message_type == "websocket.send":
            bytes_data = message.get("bytes")
            text_data = message.get("text")
            data = text_data if bytes_data is None else bytes_data
            await self.send(data)

        elif message_type == "websocket.close":
            code = message.get("code", 1000)
            await self.close(code)
            self.closed_event.set()

        else:
            msg = (
                "Expected ASGI message 'websocket.send' or 'websocket.close',"
                " but got '%s'."
            )
            raise RuntimeError(msg % message_type)

    else:
        msg = "Unexpected ASGI message '%s', after sending 'websocket.close'."
        raise RuntimeError(msg % message_type)