We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
byes_data not working with Channels consumers
Uvicorn sends its data like this:

```
        is_text = isinstance(data, str)
        return {
            "type": "websocket.receive",
            "text": data if is_text else None,
            "bytes": None if is_text else data,
        }
```

Channels generic consumers work like this:
```
    def websocket_receive(self, message):
        """
        Called when a WebSocket frame is received. Decodes it and passes it
        to receive().
        """
        if "text" in message:
            self.receive(text_data=message["text"])
        else:
            self.receive(bytes_data=message["bytes"])
```

Since `text` is present but set to none `self.receive` is called with text_data discarding the bytes_data when it is present.

I don't know if this is a bug in Uvicorn or Channels. Its a simple fix either way. Either don't set it on the dict or the channels people should check if its a truthy value and not just present.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `uvicorn/protocols/websockets/websockets_impl.py`
Content:
```
1 import asyncio
2 import http
3 from urllib.parse import unquote
4 
5 import websockets
6 
7 from uvicorn.protocols.utils import get_local_addr, get_remote_addr, is_ssl
8 
9 
10 class Server:
11     closing = False
12 
13     def register(self, ws):
14         pass
15 
16     def unregister(self, ws):
17         pass
18 
19 
20 class WebSocketProtocol(websockets.WebSocketServerProtocol):
21     def __init__(self, config, server_state, _loop=None):
22         if not config.loaded:
23             config.load()
24 
25         self.config = config
26         self.app = config.loaded_app
27         self.loop = _loop or asyncio.get_event_loop()
28         self.logger = config.logger_instance
29         self.root_path = config.root_path
30 
31         # Shared server state
32         self.connections = server_state.connections
33         self.tasks = server_state.tasks
34 
35         # Connection state
36         self.transport = None
37         self.server = None
38         self.client = None
39         self.scheme = None
40 
41         # Connection events
42         self.scope = None
43         self.handshake_started_event = asyncio.Event()
44         self.handshake_completed_event = asyncio.Event()
45         self.closed_event = asyncio.Event()
46         self.initial_response = None
47         self.connect_sent = False
48         self.accepted_subprotocol = None
49 
50         server = Server()
51 
52         super().__init__(ws_handler=self.ws_handler, ws_server=server)
53 
54     def connection_made(self, transport):
55         self.connections.add(self)
56         self.transport = transport
57         self.server = get_local_addr(transport)
58         self.client = get_remote_addr(transport)
59         self.scheme = "wss" if is_ssl(transport) else "ws"
60         super().connection_made(transport)
61 
62     def connection_lost(self, exc):
63         self.connections.remove(self)
64         self.handshake_completed_event.set()
65         super().connection_lost(exc)
66 
67     def shutdown(self):
68         self.transport.close()
69 
70     def on_task_complete(self, task):
71         self.tasks.discard(task)
72 
73     async def process_request(self, path, headers):
74         """
75         This hook is called to determine if the websocket should return
76         an HTTP response and close.
77 
78         Our behavior here is to start the ASGI application, and then wait
79         for either `accept` or `close` in order to determine if we should
80         close the connection.
81         """
82         path_portion, _, query_string = path.partition("?")
83 
84         websockets.handshake.check_request(headers)
85 
86         subprotocols = []
87         for header in headers.get_all("Sec-WebSocket-Protocol"):
88             subprotocols.extend([token.strip() for token in header.split(",")])
89 
90         asgi_headers = [
91             (name.encode("ascii"), value.encode("ascii"))
92             for name, value in headers.raw_items()
93         ]
94 
95         self.scope = {
96             "type": "websocket",
97             "scheme": self.scheme,
98             "server": self.server,
99             "client": self.client,
100             "root_path": self.root_path,
101             "path": unquote(path_portion),
102             "query_string": query_string.encode("ascii"),
103             "headers": asgi_headers,
104             "subprotocols": subprotocols,
105         }
106         task = self.loop.create_task(self.run_asgi())
107         task.add_done_callback(self.on_task_complete)
108         self.tasks.add(task)
109         await self.handshake_started_event.wait()
110         return self.initial_response
111 
112     def process_subprotocol(self, headers, available_subprotocols):
113         """
114         We override the standard 'process_subprotocol' behavior here so that
115         we return whatever subprotocol is sent in the 'accept' message.
116         """
117         return self.accepted_subprotocol
118 
119     def send_500_response(self):
120         msg = b"Internal Server Error"
121         content = [
122             b"HTTP/1.1 500 Internal Server Error\r\n"
123             b"content-type: text/plain; charset=utf-8\r\n",
124             b"content-length: " + str(len(msg)).encode("ascii") + b"\r\n",
125             b"connection: close\r\n",
126             b"\r\n",
127             msg,
128         ]
129         self.transport.write(b"".join(content))
130 
131     async def ws_handler(self, protocol, path):
132         """
133         This is the main handler function for the 'websockets' implementation
134         to call into. We just wait for close then return, and instead allow
135         'send' and 'receive' events to drive the flow.
136         """
137         self.handshake_completed_event.set()
138         await self.closed_event.wait()
139 
140     async def run_asgi(self):
141         """
142         Wrapper around the ASGI callable, handling exceptions and unexpected
143         termination states.
144         """
145         try:
146             result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
147         except BaseException as exc:
148             self.closed_event.set()
149             msg = "Exception in ASGI application\n"
150             self.logger.error(msg, exc_info=exc)
151             if not self.handshake_started_event.is_set():
152                 self.send_500_response()
153             else:
154                 await self.handshake_completed_event.wait()
155             self.transport.close()
156         else:
157             self.closed_event.set()
158             if not self.handshake_started_event.is_set():
159                 msg = "ASGI callable returned without sending handshake."
160                 self.logger.error(msg)
161                 self.send_500_response()
162                 self.transport.close()
163             elif result is not None:
164                 msg = "ASGI callable should return None, but returned '%s'."
165                 self.logger.error(msg, result)
166                 await self.handshake_completed_event.wait()
167                 self.transport.close()
168 
169     async def asgi_send(self, message):
170         message_type = message["type"]
171 
172         if not self.handshake_started_event.is_set():
173             if message_type == "websocket.accept":
174                 self.logger.info(
175                     '%s - "WebSocket %s" [accepted]',
176                     self.scope["client"],
177                     self.scope["root_path"] + self.scope["path"],
178                 )
179                 self.initial_response = None
180                 self.accepted_subprotocol = message.get("subprotocol")
181                 self.handshake_started_event.set()
182 
183             elif message_type == "websocket.close":
184                 self.logger.info(
185                     '%s - "WebSocket %s" 403',
186                     self.scope["client"],
187                     self.scope["root_path"] + self.scope["path"],
188                 )
189                 self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b"")
190                 self.handshake_started_event.set()
191                 self.closed_event.set()
192 
193             else:
194                 msg = "Expected ASGI message 'websocket.accept' or 'websocket.close', but got '%s'."
195                 raise RuntimeError(msg % message_type)
196 
197         elif not self.closed_event.is_set():
198             await self.handshake_completed_event.wait()
199 
200             if message_type == "websocket.send":
201                 bytes_data = message.get("bytes")
202                 text_data = message.get("text")
203                 data = text_data if bytes_data is None else bytes_data
204                 await self.send(data)
205 
206             elif message_type == "websocket.close":
207                 code = message.get("code", 1000)
208                 await self.close(code)
209                 self.closed_event.set()
210 
211             else:
212                 msg = "Expected ASGI message 'websocket.send' or 'websocket.close', but got '%s'."
213                 raise RuntimeError(msg % message_type)
214 
215         else:
216             msg = "Unexpected ASGI message '%s', after sending 'websocket.close'."
217             raise RuntimeError(msg % message_type)
218 
219     async def asgi_receive(self):
220         if not self.connect_sent:
221             self.connect_sent = True
222             return {"type": "websocket.connect"}
223 
224         await self.handshake_completed_event.wait()
225         try:
226             data = await self.recv()
227         except websockets.ConnectionClosed as exc:
228             return {"type": "websocket.disconnect", "code": exc.code}
229 
230         is_text = isinstance(data, str)
231         return {
232             "type": "websocket.receive",
233             "text": data if is_text else None,
234             "bytes": None if is_text else data,
235         }
236
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/uvicorn/protocols/websockets/websockets_impl.py b/uvicorn/protocols/websockets/websockets_impl.py
--- a/uvicorn/protocols/websockets/websockets_impl.py
+++ b/uvicorn/protocols/websockets/websockets_impl.py
@@ -226,9 +226,11 @@
                 "code": exc.code,
             }
 
-        is_text = isinstance(data, str)
-        return {
-            "type": "websocket.receive",
-            "text": data if is_text else None,
-            "bytes": None if is_text else data,
-        }
+        msg = {"type": "websocket.receive"}
+
+        if isinstance(data, str):
+            msg["text"] = data
+        else:
+            msg["bytes"] = data
+
+        return msg

{"golden_diff": "diff --git a/uvicorn/protocols/websockets/websockets_impl.py b/uvicorn/protocols/websockets/websockets_impl.py\n--- a/uvicorn/protocols/websockets/websockets_impl.py\n+++ b/uvicorn/protocols/websockets/websockets_impl.py\n@@ -226,9 +226,11 @@\n                 \"code\": exc.code,\n             }\n \n-        is_text = isinstance(data, str)\n-        return {\n-            \"type\": \"websocket.receive\",\n-            \"text\": data if is_text else None,\n-            \"bytes\": None if is_text else data,\n-        }\n+        msg = {\"type\": \"websocket.receive\"}\n+\n+        if isinstance(data, str):\n+            msg[\"text\"] = data\n+        else:\n+            msg[\"bytes\"] = data\n+\n+        return msg\n", "issue": "byes_data not working with Channels consumers\nUvicorn sends its data like this:\r\n\r\n```\r\n        is_text = isinstance(data, str)\r\n        return {\r\n            \"type\": \"websocket.receive\",\r\n            \"text\": data if is_text else None,\r\n            \"bytes\": None if is_text else data,\r\n        }\r\n```\r\n\r\nChannels generic consumers work like this:\r\n```\r\n    def websocket_receive(self, message):\r\n        \"\"\"\r\n        Called when a WebSocket frame is received. Decodes it and passes it\r\n        to receive().\r\n        \"\"\"\r\n        if \"text\" in message:\r\n            self.receive(text_data=message[\"text\"])\r\n        else:\r\n            self.receive(bytes_data=message[\"bytes\"])\r\n```\r\n\r\nSince `text` is present but set to none `self.receive` is called with text_data discarding the bytes_data when it is present.\r\n\r\nI don't know if this is a bug in Uvicorn or Channels. Its a simple fix either way. Either don't set it on the dict or the channels people should check if its a truthy value and not just present.\n", "before_files": [{"content": "import asyncio\nimport http\nfrom urllib.parse import unquote\n\nimport websockets\n\nfrom uvicorn.protocols.utils import get_local_addr, get_remote_addr, is_ssl\n\n\nclass Server:\n    closing = False\n\n    def register(self, ws):\n        pass\n\n    def unregister(self, ws):\n        pass\n\n\nclass WebSocketProtocol(websockets.WebSocketServerProtocol):\n    def __init__(self, config, server_state, _loop=None):\n        if not config.loaded:\n            config.load()\n\n        self.config = config\n        self.app = config.loaded_app\n        self.loop = _loop or asyncio.get_event_loop()\n        self.logger = config.logger_instance\n        self.root_path = config.root_path\n\n        # Shared server state\n        self.connections = server_state.connections\n        self.tasks = server_state.tasks\n\n        # Connection state\n        self.transport = None\n        self.server = None\n        self.client = None\n        self.scheme = None\n\n        # Connection events\n        self.scope = None\n        self.handshake_started_event = asyncio.Event()\n        self.handshake_completed_event = asyncio.Event()\n        self.closed_event = asyncio.Event()\n        self.initial_response = None\n        self.connect_sent = False\n        self.accepted_subprotocol = None\n\n        server = Server()\n\n        super().__init__(ws_handler=self.ws_handler, ws_server=server)\n\n    def connection_made(self, transport):\n        self.connections.add(self)\n        self.transport = transport\n        self.server = get_local_addr(transport)\n        self.client = get_remote_addr(transport)\n        self.scheme = \"wss\" if is_ssl(transport) else \"ws\"\n        super().connection_made(transport)\n\n    def connection_lost(self, exc):\n        self.connections.remove(self)\n        self.handshake_completed_event.set()\n        super().connection_lost(exc)\n\n    def shutdown(self):\n        self.transport.close()\n\n    def on_task_complete(self, task):\n        self.tasks.discard(task)\n\n    async def process_request(self, path, headers):\n        \"\"\"\n        This hook is called to determine if the websocket should return\n        an HTTP response and close.\n\n        Our behavior here is to start the ASGI application, and then wait\n        for either `accept` or `close` in order to determine if we should\n        close the connection.\n        \"\"\"\n        path_portion, _, query_string = path.partition(\"?\")\n\n        websockets.handshake.check_request(headers)\n\n        subprotocols = []\n        for header in headers.get_all(\"Sec-WebSocket-Protocol\"):\n            subprotocols.extend([token.strip() for token in header.split(\",\")])\n\n        asgi_headers = [\n            (name.encode(\"ascii\"), value.encode(\"ascii\"))\n            for name, value in headers.raw_items()\n        ]\n\n        self.scope = {\n            \"type\": \"websocket\",\n            \"scheme\": self.scheme,\n            \"server\": self.server,\n            \"client\": self.client,\n            \"root_path\": self.root_path,\n            \"path\": unquote(path_portion),\n            \"query_string\": query_string.encode(\"ascii\"),\n            \"headers\": asgi_headers,\n            \"subprotocols\": subprotocols,\n        }\n        task = self.loop.create_task(self.run_asgi())\n        task.add_done_callback(self.on_task_complete)\n        self.tasks.add(task)\n        await self.handshake_started_event.wait()\n        return self.initial_response\n\n    def process_subprotocol(self, headers, available_subprotocols):\n        \"\"\"\n        We override the standard 'process_subprotocol' behavior here so that\n        we return whatever subprotocol is sent in the 'accept' message.\n        \"\"\"\n        return self.accepted_subprotocol\n\n    def send_500_response(self):\n        msg = b\"Internal Server Error\"\n        content = [\n            b\"HTTP/1.1 500 Internal Server Error\\r\\n\"\n            b\"content-type: text/plain; charset=utf-8\\r\\n\",\n            b\"content-length: \" + str(len(msg)).encode(\"ascii\") + b\"\\r\\n\",\n            b\"connection: close\\r\\n\",\n            b\"\\r\\n\",\n            msg,\n        ]\n        self.transport.write(b\"\".join(content))\n\n    async def ws_handler(self, protocol, path):\n        \"\"\"\n        This is the main handler function for the 'websockets' implementation\n        to call into. We just wait for close then return, and instead allow\n        'send' and 'receive' events to drive the flow.\n        \"\"\"\n        self.handshake_completed_event.set()\n        await self.closed_event.wait()\n\n    async def run_asgi(self):\n        \"\"\"\n        Wrapper around the ASGI callable, handling exceptions and unexpected\n        termination states.\n        \"\"\"\n        try:\n            result = await self.app(self.scope, self.asgi_receive, self.asgi_send)\n        except BaseException as exc:\n            self.closed_event.set()\n            msg = \"Exception in ASGI application\\n\"\n            self.logger.error(msg, exc_info=exc)\n            if not self.handshake_started_event.is_set():\n                self.send_500_response()\n            else:\n                await self.handshake_completed_event.wait()\n            self.transport.close()\n        else:\n            self.closed_event.set()\n            if not self.handshake_started_event.is_set():\n                msg = \"ASGI callable returned without sending handshake.\"\n                self.logger.error(msg)\n                self.send_500_response()\n                self.transport.close()\n            elif result is not None:\n                msg = \"ASGI callable should return None, but returned '%s'.\"\n                self.logger.error(msg, result)\n                await self.handshake_completed_event.wait()\n                self.transport.close()\n\n    async def asgi_send(self, message):\n        message_type = message[\"type\"]\n\n        if not self.handshake_started_event.is_set():\n            if message_type == \"websocket.accept\":\n                self.logger.info(\n                    '%s - \"WebSocket %s\" [accepted]',\n                    self.scope[\"client\"],\n                    self.scope[\"root_path\"] + self.scope[\"path\"],\n                )\n                self.initial_response = None\n                self.accepted_subprotocol = message.get(\"subprotocol\")\n                self.handshake_started_event.set()\n\n            elif message_type == \"websocket.close\":\n                self.logger.info(\n                    '%s - \"WebSocket %s\" 403',\n                    self.scope[\"client\"],\n                    self.scope[\"root_path\"] + self.scope[\"path\"],\n                )\n                self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b\"\")\n                self.handshake_started_event.set()\n                self.closed_event.set()\n\n            else:\n                msg = \"Expected ASGI message 'websocket.accept' or 'websocket.close', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n        elif not self.closed_event.is_set():\n            await self.handshake_completed_event.wait()\n\n            if message_type == \"websocket.send\":\n                bytes_data = message.get(\"bytes\")\n                text_data = message.get(\"text\")\n                data = text_data if bytes_data is None else bytes_data\n                await self.send(data)\n\n            elif message_type == \"websocket.close\":\n                code = message.get(\"code\", 1000)\n                await self.close(code)\n                self.closed_event.set()\n\n            else:\n                msg = \"Expected ASGI message 'websocket.send' or 'websocket.close', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n        else:\n            msg = \"Unexpected ASGI message '%s', after sending 'websocket.close'.\"\n            raise RuntimeError(msg % message_type)\n\n    async def asgi_receive(self):\n        if not self.connect_sent:\n            self.connect_sent = True\n            return {\"type\": \"websocket.connect\"}\n\n        await self.handshake_completed_event.wait()\n        try:\n            data = await self.recv()\n        except websockets.ConnectionClosed as exc:\n            return {\"type\": \"websocket.disconnect\", \"code\": exc.code}\n\n        is_text = isinstance(data, str)\n        return {\n            \"type\": \"websocket.receive\",\n            \"text\": data if is_text else None,\n            \"bytes\": None if is_text else data,\n        }\n", "path": "uvicorn/protocols/websockets/websockets_impl.py"}], "after_files": [{"content": "from urllib.parse import unquote\nfrom uvicorn.protocols.utils import get_local_addr, get_remote_addr, is_ssl\nimport asyncio\nimport http\nimport logging\nimport websockets\n\n\nclass Server:\n    closing = False\n\n    def register(self, ws):\n        pass\n\n    def unregister(self, ws):\n        pass\n\n\nclass WebSocketProtocol(websockets.WebSocketServerProtocol):\n    def __init__(self, app, connections=None, tasks=None, loop=None, logger=None):\n        self.app = app\n        self.root_path = ''\n        self.connections = set() if connections is None else connections\n        self.tasks = set() if tasks is None else tasks\n        self.loop = loop or asyncio.get_event_loop()\n        self.logger = logger or logging.getLogger(\"uvicorn\")\n\n        # Connection state\n        self.transport = None\n        self.server = None\n        self.client = None\n        self.scheme = None\n\n        # Connection events\n        self.scope = None\n        self.handshake_started_event = asyncio.Event()\n        self.handshake_completed_event = asyncio.Event()\n        self.closed_event = asyncio.Event()\n        self.initial_response = None\n        self.connect_sent = False\n        self.accepted_subprotocol = None\n\n        server = Server()\n\n        super().__init__(ws_handler=self.ws_handler, ws_server=server)\n\n    def connection_made(self, transport):\n        self.connections.add(self)\n        self.transport = transport\n        self.server = get_local_addr(transport)\n        self.client = get_remote_addr(transport)\n        self.scheme = \"wss\" if is_ssl(transport) else \"ws\"\n        super().connection_made(transport)\n\n    def connection_lost(self, exc):\n        self.connections.remove(self)\n        self.handshake_completed_event.set()\n        super().connection_lost(exc)\n\n    def shutdown(self):\n        self.transport.close()\n\n    def on_task_complete(self, task):\n        self.tasks.discard(task)\n\n    async def process_request(self, path, headers):\n        \"\"\"\n        This hook is called to determine if the websocket should return\n        an HTTP response and close.\n\n        Our behavior here is to start the ASGI application, and then wait\n        for either `accept` or `close` in order to determine if we should\n        close the connection.\n        \"\"\"\n        path_portion, _, query_string = path.partition('?')\n\n        websockets.handshake.check_request(headers)\n\n        subprotocols = []\n        for header in headers.get_all('Sec-WebSocket-Protocol'):\n            subprotocols.extend([token.strip() for token in header.split(',')])\n\n        asgi_headers = [\n            (name.encode('ascii'), value.encode('ascii'))\n            for name, value in headers.raw_items()\n        ]\n\n        self.scope = {\n            'type': 'websocket',\n            'scheme': self.scheme,\n            'server': self.server,\n            'client': self.client,\n            'root_path': self.root_path,\n            'path': unquote(path_portion),\n            'query_string': query_string.encode('ascii'),\n            'headers': asgi_headers,\n            'subprotocols': subprotocols,\n        }\n        task = self.loop.create_task(self.run_asgi())\n        task.add_done_callback(self.on_task_complete)\n        self.tasks.add(task)\n        await self.handshake_started_event.wait()\n        return self.initial_response\n\n    def process_subprotocol(self, headers, available_subprotocols):\n        \"\"\"\n        We override the standard 'process_subprotocol' behavior here so that\n        we return whatever subprotocol is sent in the 'accept' message.\n        \"\"\"\n        return self.accepted_subprotocol\n\n    def send_500_response(self):\n        msg = b\"Internal Server Error\"\n        content = [\n            b\"HTTP/1.1 500 Internal Server Error\\r\\n\"\n            b\"content-type: text/plain; charset=utf-8\\r\\n\",\n            b\"content-length: \" + str(len(msg)).encode('ascii') + b\"\\r\\n\",\n            b\"connection: close\\r\\n\",\n            b\"\\r\\n\",\n            msg\n        ]\n        self.transport.write(b\"\".join(content))\n\n    async def ws_handler(self, protocol, path):\n        \"\"\"\n        This is the main handler function for the 'websockets' implementation\n        to call into. We just wait for close then return, and instead allow\n        'send' and 'receive' events to drive the flow.\n        \"\"\"\n        self.handshake_completed_event.set()\n        await self.closed_event.wait()\n\n    async def run_asgi(self):\n        \"\"\"\n        Wrapper around the ASGI callable, handling exceptions and unexpected\n        termination states.\n        \"\"\"\n        try:\n            asgi = self.app(self.scope)\n            result = await asgi(self.asgi_receive, self.asgi_send)\n        except BaseException as exc:\n            self.closed_event.set()\n            msg = \"Exception in ASGI application\\n\"\n            self.logger.error(msg, exc_info=exc)\n            if not self.handshake_started_event.is_set():\n                self.send_500_response()\n            else:\n                await self.handshake_completed_event.wait()\n            self.transport.close()\n        else:\n            self.closed_event.set()\n            if not self.handshake_started_event.is_set():\n                msg = \"ASGI callable returned without sending handshake.\"\n                self.logger.error(msg)\n                self.send_500_response()\n                self.transport.close()\n            elif result is not None:\n                msg = \"ASGI callable should return None, but returned '%s'.\"\n                self.logger.error(msg, result)\n                await self.handshake_completed_event.wait()\n                self.transport.close()\n\n    async def asgi_send(self, message):\n        message_type = message[\"type\"]\n\n        if not self.handshake_started_event.is_set():\n            if message_type == \"websocket.accept\":\n                self.logger.info(\n                    '%s - \"WebSocket %s\" [accepted]',\n                    self.scope[\"server\"][0],\n                    self.scope[\"path\"],\n                )\n                self.initial_response = None\n                self.accepted_subprotocol = message.get('subprotocol')\n                self.handshake_started_event.set()\n\n            elif message_type == \"websocket.close\":\n                self.logger.info(\n                    '%s - \"WebSocket %s\" 403',\n                    self.scope[\"server\"][0],\n                    self.scope[\"path\"],\n                )\n                self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b'')\n                self.handshake_started_event.set()\n                self.closed_event.set()\n\n            else:\n                msg = \"Expected ASGI message 'websocket.accept' or 'websocket.close', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n        elif not self.closed_event.is_set():\n            await self.handshake_completed_event.wait()\n\n            if message_type == 'websocket.send':\n                bytes_data = message.get('bytes')\n                text_data = message.get('text')\n                data = text_data if bytes_data is None else bytes_data\n                await self.send(data)\n\n            elif message_type == 'websocket.close':\n                code = message.get('code', 1000)\n                await self.close(code)\n                self.closed_event.set()\n\n            else:\n                msg = \"Expected ASGI message 'websocket.send' or 'websocket.close', but got '%s'.\"\n                raise RuntimeError(msg % message_type)\n\n        else:\n            msg = \"Unexpected ASGI message '%s', after sending 'websocket.close'.\"\n            raise RuntimeError(msg % message_type)\n\n    async def asgi_receive(self):\n        if not self.connect_sent:\n            self.connect_sent = True\n            return {\n                \"type\": \"websocket.connect\"\n            }\n\n        await self.handshake_completed_event.wait()\n        try:\n            data = await self.recv()\n        except websockets.ConnectionClosed as exc:\n            return {\n                \"type\": \"websocket.disconnect\",\n                \"code\": exc.code,\n            }\n\n        msg = {\"type\": \"websocket.receive\"}\n\n        if isinstance(data, str):\n            msg[\"text\"] = data\n        else:\n            msg[\"bytes\"] = data\n\n        return msg\n", "path": "uvicorn/protocols/websockets/websockets_impl.py"}]}