ErisPulse-QQBotAdapter 4.0.1__tar.gz → 4.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse-QQBotAdapter
3
- Version: 4.0.1
3
+ Version: 4.0.2
4
4
  Summary: ErisPulse的QQ官方机器人适配模块
5
5
  Author-email: wsu2059 <wsu2059@qq.com>
6
6
  Project-URL: homepage, https://github.com/ErisPulse/ErisPulse-QQBotAdapter
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse-QQBotAdapter
3
- Version: 4.0.1
3
+ Version: 4.0.2
4
4
  Summary: ErisPulse的QQ官方机器人适配模块
5
5
  Author-email: wsu2059 <wsu2059@qq.com>
6
6
  Project-URL: homepage, https://github.com/ErisPulse/ErisPulse-QQBotAdapter
@@ -30,6 +30,8 @@ class QQBotWebSocket:
30
30
  self._reconnect_count = 0
31
31
  self._max_reconnect = 50
32
32
  self._closing = False
33
+ self._reconnect_lock = asyncio.Lock()
34
+ self._reconnect_task: Optional[asyncio.Task] = None
33
35
 
34
36
  async def connect(self):
35
37
  gateway_url = self.adapter.config.get("gateway_url", "wss://api.sgroup.qq.com/websocket/")
@@ -64,7 +66,7 @@ class QQBotWebSocket:
64
66
 
65
67
  except Exception as e:
66
68
  self.adapter.logger.error(f"WebSocket 连接失败: {e}")
67
- await self._reconnect()
69
+ self._schedule_reconnect()
68
70
 
69
71
  async def _identify(self):
70
72
  token = await self.adapter._ensure_token()
@@ -109,7 +111,7 @@ class QQBotWebSocket:
109
111
  pass
110
112
  except Exception as e:
111
113
  self.adapter.logger.error(f"心跳循环异常: {e}")
112
- await self._reconnect()
114
+ self._schedule_reconnect()
113
115
 
114
116
  async def _listen(self):
115
117
  try:
@@ -122,13 +124,13 @@ class QQBotWebSocket:
122
124
  self.adapter.logger.warning(f"WebSocket 关闭: {msg.type}")
123
125
  break
124
126
  except asyncio.CancelledError:
125
- pass
127
+ return
126
128
  except Exception as e:
127
129
  self.adapter.logger.error(f"监听异常: {e}")
128
130
  finally:
129
131
  self._connected = False
130
- if not self._closing and (not self.listen_task or not self.listen_task.cancelled()):
131
- await self._reconnect()
132
+ if not self._closing:
133
+ self._schedule_reconnect()
132
134
 
133
135
  async def _handle_message(self, data: dict):
134
136
  op = data.get("op")
@@ -163,50 +165,68 @@ class QQBotWebSocket:
163
165
 
164
166
  elif op == self.OP_RECONNECT:
165
167
  self.adapter.logger.warning("收到 Reconnect 指令,重新连接")
166
- await self._reconnect()
168
+ self._schedule_reconnect()
167
169
 
168
170
  elif op == self.OP_INVALID_SESSION:
169
171
  self.adapter.logger.warning("会话无效,重新 Identify")
170
172
  self.session_id = None
171
173
  self.seq = None
172
- await self._reconnect()
174
+ self._schedule_reconnect()
173
175
 
174
176
  elif op == self.OP_HELLO:
175
177
  data_inner = d if d else {}
176
178
  self.heartbeat_interval = data_inner.get("heartbeat_interval", 45000)
177
179
 
180
+ def _schedule_reconnect(self):
181
+ if self._closing:
182
+ return
183
+ if self._reconnect_task and not self._reconnect_task.done():
184
+ return
185
+ self._reconnect_task = asyncio.create_task(self._reconnect())
186
+
178
187
  async def _reconnect(self):
179
188
  if self._closing:
180
189
  return
181
190
 
182
- if self.heartbeat_task:
183
- self.heartbeat_task.cancel()
184
- try:
185
- await self.heartbeat_task
186
- except asyncio.CancelledError:
187
- pass
188
- self.heartbeat_task = None
191
+ async with self._reconnect_lock:
192
+ self._connected = False
189
193
 
190
- self._reconnect_count += 1
191
- if self._reconnect_count > self._max_reconnect:
192
- self.adapter.logger.error("已达到最大重连次数,停止重连")
193
- return
194
+ if self.heartbeat_task:
195
+ self.heartbeat_task.cancel()
196
+ try:
197
+ await self.heartbeat_task
198
+ except asyncio.CancelledError:
199
+ pass
200
+ self.heartbeat_task = None
194
201
 
195
- wait_time = min(5 * (2 ** min(self._reconnect_count, 6)), 300)
196
- self.adapter.logger.warning(f"{wait_time}秒后尝试第 {self._reconnect_count} 次重连")
197
- await asyncio.sleep(wait_time)
202
+ if self.listen_task:
203
+ self.listen_task.cancel()
204
+ try:
205
+ await self.listen_task
206
+ except asyncio.CancelledError:
207
+ pass
208
+ self.listen_task = None
198
209
 
199
- if self._closing:
200
- return
210
+ self._reconnect_count += 1
211
+ if self._reconnect_count > self._max_reconnect:
212
+ self.adapter.logger.error("已达到最大重连次数,停止重连")
213
+ return
201
214
 
202
- try:
203
- if self.ws and not self.ws.closed:
204
- await self.ws.close()
205
- except Exception:
206
- pass
215
+ wait_time = min(5 * (2 ** min(self._reconnect_count, 6)), 300)
216
+ self.adapter.logger.warning(f"{wait_time}秒后尝试第 {self._reconnect_count} 次重连")
217
+ await asyncio.sleep(wait_time)
207
218
 
208
- gateway_url = self.adapter.config.get("gateway_url", "wss://api.sgroup.qq.com/websocket/")
209
- await self._connect(gateway_url)
219
+ if self._closing:
220
+ return
221
+
222
+ try:
223
+ if self.ws and not self.ws.closed:
224
+ await self.ws.close()
225
+ except Exception:
226
+ pass
227
+
228
+ gateway_url = self.adapter.config.get("gateway_url", "wss://api.sgroup.qq.com/websocket/")
229
+ await self._connect(gateway_url)
210
230
 
211
231
  async def start_token_refresh(self):
212
232
  self._token_refresh_task = asyncio.create_task(self._token_refresh_loop())
@@ -226,6 +246,14 @@ class QQBotWebSocket:
226
246
  self._closing = True
227
247
  self._connected = False
228
248
 
249
+ if self._reconnect_task:
250
+ self._reconnect_task.cancel()
251
+ try:
252
+ await self._reconnect_task
253
+ except asyncio.CancelledError:
254
+ pass
255
+ self._reconnect_task = None
256
+
229
257
  if self._token_refresh_task:
230
258
  self._token_refresh_task.cancel()
231
259
  try:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ErisPulse-QQBotAdapter"
3
- version = "4.0.1"
3
+ version = "4.0.2"
4
4
  description = "ErisPulse的QQ官方机器人适配模块"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"