We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bug: websockets 驱动器连接关闭 code 不存在
### 操作系统

Windows

### Python 版本

3.11.6

### NoneBot 版本

2.1.2

### 适配器

nonebot-adapter-kaiheila 0.3.0

### 协议端

kook API(websockets)

### 描述问题

在nonebot库的websockets.py模块中，处理WebSocket异常时出现了AttributeError。这个问题发生在尝试处理ConnectionClosed异常的过程中。
异常信息:
`AttributeError: 'NoneType' object has no attribute 'code'`
相关代码:
```python
def catch_closed(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:
    @wraps(func)
    async def decorator(*args: P.args, **kwargs: P.kwargs) -> T:
        try:
            return await func(*args, **kwargs)
        except ConnectionClosed as e:
            if e.rcvd_then_sent:
                raise WebSocketClosed(e.rcvd.code, e.rcvd.reason)  # type: ignore
            else:
                raise WebSocketClosed(e.sent.code, e.sent.reason)  # type: ignore

    return decorator
```

位于:`nonebot/drivers/websockets.py` Line 56
这个问题是在捕获ConnectionClosed异常时发生的，但e.rcvd或e.sent对象可能为None(在websocket超时这种不是由关闭帧影响的情况下会都不存在)。这导致尝试访问NoneType对象的code属性，从而引发了AttributeError。

### 复现步骤

1.在环境下加载websockets adapter
2.在插件的event handler中存在不使用异步的长时间等待情形（在我的例子是等待语言模型的计算）


### 期望的结果

按照上述描述修改此bug

### 截图或日志

无

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nonebot/drivers/websockets.py`
Content:
```
1 """[websockets](https://websockets.readthedocs.io/) 驱动适配
2 
3 ```bash
4 nb driver install websockets
5 # 或者
6 pip install nonebot2[websockets]
7 ```
8 
9 :::tip 提示
10 本驱动仅支持客户端 WebSocket 连接
11 :::
12 
13 FrontMatter:
14     sidebar_position: 4
15     description: nonebot.drivers.websockets 模块
16 """
17 
18 import logging
19 from functools import wraps
20 from contextlib import asynccontextmanager
21 from typing_extensions import ParamSpec, override
22 from typing import TYPE_CHECKING, Union, TypeVar, Callable, Awaitable, AsyncGenerator
23 
24 from nonebot.drivers import Request
25 from nonebot.log import LoguruHandler
26 from nonebot.exception import WebSocketClosed
27 from nonebot.drivers.none import Driver as NoneDriver
28 from nonebot.drivers import WebSocket as BaseWebSocket
29 from nonebot.drivers import WebSocketClientMixin, combine_driver
30 
31 try:
32     from websockets.exceptions import ConnectionClosed
33     from websockets.legacy.client import Connect, WebSocketClientProtocol
34 except ModuleNotFoundError as e:  # pragma: no cover
35     raise ImportError(
36         "Please install websockets first to use this driver. "
37         "Install with pip: `pip install nonebot2[websockets]`"
38     ) from e
39 
40 T = TypeVar("T")
41 P = ParamSpec("P")
42 
43 logger = logging.Logger("websockets.client", "INFO")
44 logger.addHandler(LoguruHandler())
45 
46 
47 def catch_closed(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:
48     @wraps(func)
49     async def decorator(*args: P.args, **kwargs: P.kwargs) -> T:
50         try:
51             return await func(*args, **kwargs)
52         except ConnectionClosed as e:
53             if e.rcvd_then_sent:
54                 raise WebSocketClosed(e.rcvd.code, e.rcvd.reason)  # type: ignore
55             else:
56                 raise WebSocketClosed(e.sent.code, e.sent.reason)  # type: ignore
57 
58     return decorator
59 
60 
61 class Mixin(WebSocketClientMixin):
62     """Websockets Mixin"""
63 
64     @property
65     @override
66     def type(self) -> str:
67         return "websockets"
68 
69     @override
70     @asynccontextmanager
71     async def websocket(self, setup: Request) -> AsyncGenerator["WebSocket", None]:
72         connection = Connect(
73             str(setup.url),
74             extra_headers={**setup.headers, **setup.cookies.as_header(setup)},
75             open_timeout=setup.timeout,
76         )
77         async with connection as ws:
78             yield WebSocket(request=setup, websocket=ws)
79 
80 
81 class WebSocket(BaseWebSocket):
82     """Websockets WebSocket Wrapper"""
83 
84     @override
85     def __init__(self, *, request: Request, websocket: WebSocketClientProtocol):
86         super().__init__(request=request)
87         self.websocket = websocket
88 
89     @property
90     @override
91     def closed(self) -> bool:
92         return self.websocket.closed
93 
94     @override
95     async def accept(self):
96         raise NotImplementedError
97 
98     @override
99     async def close(self, code: int = 1000, reason: str = ""):
100         await self.websocket.close(code, reason)
101 
102     @override
103     @catch_closed
104     async def receive(self) -> Union[str, bytes]:
105         return await self.websocket.recv()
106 
107     @override
108     @catch_closed
109     async def receive_text(self) -> str:
110         msg = await self.websocket.recv()
111         if isinstance(msg, bytes):
112             raise TypeError("WebSocket received unexpected frame type: bytes")
113         return msg
114 
115     @override
116     @catch_closed
117     async def receive_bytes(self) -> bytes:
118         msg = await self.websocket.recv()
119         if isinstance(msg, str):
120             raise TypeError("WebSocket received unexpected frame type: str")
121         return msg
122 
123     @override
124     async def send_text(self, data: str) -> None:
125         await self.websocket.send(data)
126 
127     @override
128     async def send_bytes(self, data: bytes) -> None:
129         await self.websocket.send(data)
130 
131 
132 if TYPE_CHECKING:
133 
134     class Driver(Mixin, NoneDriver):
135         ...
136 
137 else:
138     Driver = combine_driver(NoneDriver, Mixin)
139     """Websockets Driver"""
140
```
--- 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/nonebot/drivers/websockets.py b/nonebot/drivers/websockets.py
--- a/nonebot/drivers/websockets.py
+++ b/nonebot/drivers/websockets.py
@@ -50,10 +50,7 @@
         try:
             return await func(*args, **kwargs)
         except ConnectionClosed as e:
-            if e.rcvd_then_sent:
-                raise WebSocketClosed(e.rcvd.code, e.rcvd.reason)  # type: ignore
-            else:
-                raise WebSocketClosed(e.sent.code, e.sent.reason)  # type: ignore
+            raise WebSocketClosed(e.code, e.reason)
 
     return decorator

{"golden_diff": "diff --git a/nonebot/drivers/websockets.py b/nonebot/drivers/websockets.py\n--- a/nonebot/drivers/websockets.py\n+++ b/nonebot/drivers/websockets.py\n@@ -50,10 +50,7 @@\n         try:\n             return await func(*args, **kwargs)\n         except ConnectionClosed as e:\n-            if e.rcvd_then_sent:\n-                raise WebSocketClosed(e.rcvd.code, e.rcvd.reason)  # type: ignore\n-            else:\n-                raise WebSocketClosed(e.sent.code, e.sent.reason)  # type: ignore\n+            raise WebSocketClosed(e.code, e.reason)\n \n     return decorator\n", "issue": "Bug: websockets \u9a71\u52a8\u5668\u8fde\u63a5\u5173\u95ed code \u4e0d\u5b58\u5728\n### \u64cd\u4f5c\u7cfb\u7edf\r\n\r\nWindows\r\n\r\n### Python \u7248\u672c\r\n\r\n3.11.6\r\n\r\n### NoneBot \u7248\u672c\r\n\r\n2.1.2\r\n\r\n### \u9002\u914d\u5668\r\n\r\nnonebot-adapter-kaiheila 0.3.0\r\n\r\n### \u534f\u8bae\u7aef\r\n\r\nkook API(websockets)\r\n\r\n### \u63cf\u8ff0\u95ee\u9898\r\n\r\n\u5728nonebot\u5e93\u7684websockets.py\u6a21\u5757\u4e2d\uff0c\u5904\u7406WebSocket\u5f02\u5e38\u65f6\u51fa\u73b0\u4e86AttributeError\u3002\u8fd9\u4e2a\u95ee\u9898\u53d1\u751f\u5728\u5c1d\u8bd5\u5904\u7406ConnectionClosed\u5f02\u5e38\u7684\u8fc7\u7a0b\u4e2d\u3002\r\n\u5f02\u5e38\u4fe1\u606f:\r\n`AttributeError: 'NoneType' object has no attribute 'code'`\r\n\u76f8\u5173\u4ee3\u7801:\r\n```python\r\ndef catch_closed(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:\r\n    @wraps(func)\r\n    async def decorator(*args: P.args, **kwargs: P.kwargs) -> T:\r\n        try:\r\n            return await func(*args, **kwargs)\r\n        except ConnectionClosed as e:\r\n            if e.rcvd_then_sent:\r\n                raise WebSocketClosed(e.rcvd.code, e.rcvd.reason)  # type: ignore\r\n            else:\r\n                raise WebSocketClosed(e.sent.code, e.sent.reason)  # type: ignore\r\n\r\n    return decorator\r\n```\r\n\r\n\u4f4d\u4e8e:`nonebot/drivers/websockets.py` Line 56\r\n\u8fd9\u4e2a\u95ee\u9898\u662f\u5728\u6355\u83b7ConnectionClosed\u5f02\u5e38\u65f6\u53d1\u751f\u7684\uff0c\u4f46e.rcvd\u6216e.sent\u5bf9\u8c61\u53ef\u80fd\u4e3aNone(\u5728websocket\u8d85\u65f6\u8fd9\u79cd\u4e0d\u662f\u7531\u5173\u95ed\u5e27\u5f71\u54cd\u7684\u60c5\u51b5\u4e0b\u4f1a\u90fd\u4e0d\u5b58\u5728)\u3002\u8fd9\u5bfc\u81f4\u5c1d\u8bd5\u8bbf\u95eeNoneType\u5bf9\u8c61\u7684code\u5c5e\u6027\uff0c\u4ece\u800c\u5f15\u53d1\u4e86AttributeError\u3002\r\n\r\n### \u590d\u73b0\u6b65\u9aa4\r\n\r\n1.\u5728\u73af\u5883\u4e0b\u52a0\u8f7dwebsockets adapter\r\n2.\u5728\u63d2\u4ef6\u7684event handler\u4e2d\u5b58\u5728\u4e0d\u4f7f\u7528\u5f02\u6b65\u7684\u957f\u65f6\u95f4\u7b49\u5f85\u60c5\u5f62\uff08\u5728\u6211\u7684\u4f8b\u5b50\u662f\u7b49\u5f85\u8bed\u8a00\u6a21\u578b\u7684\u8ba1\u7b97\uff09\r\n\r\n\r\n### \u671f\u671b\u7684\u7ed3\u679c\r\n\r\n\u6309\u7167\u4e0a\u8ff0\u63cf\u8ff0\u4fee\u6539\u6b64bug\r\n\r\n### \u622a\u56fe\u6216\u65e5\u5fd7\r\n\r\n\u65e0\n", "before_files": [{"content": "\"\"\"[websockets](https://websockets.readthedocs.io/) \u9a71\u52a8\u9002\u914d\n\n```bash\nnb driver install websockets\n# \u6216\u8005\npip install nonebot2[websockets]\n```\n\n:::tip \u63d0\u793a\n\u672c\u9a71\u52a8\u4ec5\u652f\u6301\u5ba2\u6237\u7aef WebSocket \u8fde\u63a5\n:::\n\nFrontMatter:\n    sidebar_position: 4\n    description: nonebot.drivers.websockets \u6a21\u5757\n\"\"\"\n\nimport logging\nfrom functools import wraps\nfrom contextlib import asynccontextmanager\nfrom typing_extensions import ParamSpec, override\nfrom typing import TYPE_CHECKING, Union, TypeVar, Callable, Awaitable, AsyncGenerator\n\nfrom nonebot.drivers import Request\nfrom nonebot.log import LoguruHandler\nfrom nonebot.exception import WebSocketClosed\nfrom nonebot.drivers.none import Driver as NoneDriver\nfrom nonebot.drivers import WebSocket as BaseWebSocket\nfrom nonebot.drivers import WebSocketClientMixin, combine_driver\n\ntry:\n    from websockets.exceptions import ConnectionClosed\n    from websockets.legacy.client import Connect, WebSocketClientProtocol\nexcept ModuleNotFoundError as e:  # pragma: no cover\n    raise ImportError(\n        \"Please install websockets first to use this driver. \"\n        \"Install with pip: `pip install nonebot2[websockets]`\"\n    ) from e\n\nT = TypeVar(\"T\")\nP = ParamSpec(\"P\")\n\nlogger = logging.Logger(\"websockets.client\", \"INFO\")\nlogger.addHandler(LoguruHandler())\n\n\ndef catch_closed(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:\n    @wraps(func)\n    async def decorator(*args: P.args, **kwargs: P.kwargs) -> T:\n        try:\n            return await func(*args, **kwargs)\n        except ConnectionClosed as e:\n            if e.rcvd_then_sent:\n                raise WebSocketClosed(e.rcvd.code, e.rcvd.reason)  # type: ignore\n            else:\n                raise WebSocketClosed(e.sent.code, e.sent.reason)  # type: ignore\n\n    return decorator\n\n\nclass Mixin(WebSocketClientMixin):\n    \"\"\"Websockets Mixin\"\"\"\n\n    @property\n    @override\n    def type(self) -> str:\n        return \"websockets\"\n\n    @override\n    @asynccontextmanager\n    async def websocket(self, setup: Request) -> AsyncGenerator[\"WebSocket\", None]:\n        connection = Connect(\n            str(setup.url),\n            extra_headers={**setup.headers, **setup.cookies.as_header(setup)},\n            open_timeout=setup.timeout,\n        )\n        async with connection as ws:\n            yield WebSocket(request=setup, websocket=ws)\n\n\nclass WebSocket(BaseWebSocket):\n    \"\"\"Websockets WebSocket Wrapper\"\"\"\n\n    @override\n    def __init__(self, *, request: Request, websocket: WebSocketClientProtocol):\n        super().__init__(request=request)\n        self.websocket = websocket\n\n    @property\n    @override\n    def closed(self) -> bool:\n        return self.websocket.closed\n\n    @override\n    async def accept(self):\n        raise NotImplementedError\n\n    @override\n    async def close(self, code: int = 1000, reason: str = \"\"):\n        await self.websocket.close(code, reason)\n\n    @override\n    @catch_closed\n    async def receive(self) -> Union[str, bytes]:\n        return await self.websocket.recv()\n\n    @override\n    @catch_closed\n    async def receive_text(self) -> str:\n        msg = await self.websocket.recv()\n        if isinstance(msg, bytes):\n            raise TypeError(\"WebSocket received unexpected frame type: bytes\")\n        return msg\n\n    @override\n    @catch_closed\n    async def receive_bytes(self) -> bytes:\n        msg = await self.websocket.recv()\n        if isinstance(msg, str):\n            raise TypeError(\"WebSocket received unexpected frame type: str\")\n        return msg\n\n    @override\n    async def send_text(self, data: str) -> None:\n        await self.websocket.send(data)\n\n    @override\n    async def send_bytes(self, data: bytes) -> None:\n        await self.websocket.send(data)\n\n\nif TYPE_CHECKING:\n\n    class Driver(Mixin, NoneDriver):\n        ...\n\nelse:\n    Driver = combine_driver(NoneDriver, Mixin)\n    \"\"\"Websockets Driver\"\"\"\n", "path": "nonebot/drivers/websockets.py"}], "after_files": [{"content": "\"\"\"[websockets](https://websockets.readthedocs.io/) \u9a71\u52a8\u9002\u914d\n\n```bash\nnb driver install websockets\n# \u6216\u8005\npip install nonebot2[websockets]\n```\n\n:::tip \u63d0\u793a\n\u672c\u9a71\u52a8\u4ec5\u652f\u6301\u5ba2\u6237\u7aef WebSocket \u8fde\u63a5\n:::\n\nFrontMatter:\n    sidebar_position: 4\n    description: nonebot.drivers.websockets \u6a21\u5757\n\"\"\"\n\nimport logging\nfrom functools import wraps\nfrom contextlib import asynccontextmanager\nfrom typing_extensions import ParamSpec, override\nfrom typing import TYPE_CHECKING, Union, TypeVar, Callable, Awaitable, AsyncGenerator\n\nfrom nonebot.drivers import Request\nfrom nonebot.log import LoguruHandler\nfrom nonebot.exception import WebSocketClosed\nfrom nonebot.drivers.none import Driver as NoneDriver\nfrom nonebot.drivers import WebSocket as BaseWebSocket\nfrom nonebot.drivers import WebSocketClientMixin, combine_driver\n\ntry:\n    from websockets.exceptions import ConnectionClosed\n    from websockets.legacy.client import Connect, WebSocketClientProtocol\nexcept ModuleNotFoundError as e:  # pragma: no cover\n    raise ImportError(\n        \"Please install websockets first to use this driver. \"\n        \"Install with pip: `pip install nonebot2[websockets]`\"\n    ) from e\n\nT = TypeVar(\"T\")\nP = ParamSpec(\"P\")\n\nlogger = logging.Logger(\"websockets.client\", \"INFO\")\nlogger.addHandler(LoguruHandler())\n\n\ndef catch_closed(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:\n    @wraps(func)\n    async def decorator(*args: P.args, **kwargs: P.kwargs) -> T:\n        try:\n            return await func(*args, **kwargs)\n        except ConnectionClosed as e:\n            raise WebSocketClosed(e.code, e.reason)\n\n    return decorator\n\n\nclass Mixin(WebSocketClientMixin):\n    \"\"\"Websockets Mixin\"\"\"\n\n    @property\n    @override\n    def type(self) -> str:\n        return \"websockets\"\n\n    @override\n    @asynccontextmanager\n    async def websocket(self, setup: Request) -> AsyncGenerator[\"WebSocket\", None]:\n        connection = Connect(\n            str(setup.url),\n            extra_headers={**setup.headers, **setup.cookies.as_header(setup)},\n            open_timeout=setup.timeout,\n        )\n        async with connection as ws:\n            yield WebSocket(request=setup, websocket=ws)\n\n\nclass WebSocket(BaseWebSocket):\n    \"\"\"Websockets WebSocket Wrapper\"\"\"\n\n    @override\n    def __init__(self, *, request: Request, websocket: WebSocketClientProtocol):\n        super().__init__(request=request)\n        self.websocket = websocket\n\n    @property\n    @override\n    def closed(self) -> bool:\n        return self.websocket.closed\n\n    @override\n    async def accept(self):\n        raise NotImplementedError\n\n    @override\n    async def close(self, code: int = 1000, reason: str = \"\"):\n        await self.websocket.close(code, reason)\n\n    @override\n    @catch_closed\n    async def receive(self) -> Union[str, bytes]:\n        return await self.websocket.recv()\n\n    @override\n    @catch_closed\n    async def receive_text(self) -> str:\n        msg = await self.websocket.recv()\n        if isinstance(msg, bytes):\n            raise TypeError(\"WebSocket received unexpected frame type: bytes\")\n        return msg\n\n    @override\n    @catch_closed\n    async def receive_bytes(self) -> bytes:\n        msg = await self.websocket.recv()\n        if isinstance(msg, str):\n            raise TypeError(\"WebSocket received unexpected frame type: str\")\n        return msg\n\n    @override\n    async def send_text(self, data: str) -> None:\n        await self.websocket.send(data)\n\n    @override\n    async def send_bytes(self, data: bytes) -> None:\n        await self.websocket.send(data)\n\n\nif TYPE_CHECKING:\n\n    class Driver(Mixin, NoneDriver):\n        ...\n\nelse:\n    Driver = combine_driver(NoneDriver, Mixin)\n    \"\"\"Websockets Driver\"\"\"\n", "path": "nonebot/drivers/websockets.py"}]}