CheeseAPI 2.0.8b5__tar.gz → 2.0.8b7__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.
@@ -267,7 +267,7 @@ class RequestProxy:
267
267
  name = None
268
268
  filename = None
269
269
  for line in headers.decode().strip().split('\r\n'):
270
- if line.startswith('content-disposition:'):
270
+ if line.startswith('Content-Disposition:'):
271
271
  name_match = re.search(r'name="([^"]*)"', line)
272
272
  if name_match:
273
273
  name = name_match.group(1)
@@ -1,4 +1,4 @@
1
- import base64, hashlib, asyncio, ssl, struct, json
1
+ import base64, hashlib, asyncio, ssl, struct, json, inspect
2
2
  from functools import partial
3
3
  from typing import TYPE_CHECKING, AsyncIterable, Self
4
4
 
@@ -48,8 +48,8 @@ class Websocket:
48
48
  self._request: 'Request' = request
49
49
 
50
50
  self._proxy: 'WebsocketProxy' = request._proxy.app.WebsocketProxy_Class(request._proxy.app, self)
51
- self._key: str = self.request.headers.get('sec-websocket-key')
52
- subprotocols = self.request.headers.get('sec-websocket-protocol')
51
+ self._key: str = self.request.headers.get('sec-websocket-key') or self.request.headers.get('Sec-WebSocket-Key')
52
+ subprotocols = self.request.headers.get('sec-websocket-protocol') or self.request.headers.get('Sec-WebSocket-Protocol')
53
53
  self._subprotocols: list[str] | None = subprotocols.strip().split(',') if subprotocols else None
54
54
  self._subprotocol: str | None = None
55
55
  self.response: Response | None = None
@@ -109,6 +109,8 @@ class Websocket:
109
109
  close = DualMethod(_static_close, _instance_close)
110
110
 
111
111
  class WebsocketProxy:
112
+ _sync_tasks: dict[str, asyncio.Task] = {}
113
+
112
114
  @staticmethod
113
115
  def _static_send(path: str, data: bytes | list | str | dict, *, websocket_key_or_keys: str | list[str] | None = None):
114
116
  if static.websocket_sync_servers is not None:
@@ -223,19 +225,21 @@ class WebsocketProxy:
223
225
  await self.message()
224
226
  await self.disconnect()
225
227
  except Exception as e:
226
- await self.app.printer.websocket_error(e, self.websocket)
228
+ result = self.app.printer.websocket_error(e, self.websocket)
229
+ if inspect.isawaitable(result):
230
+ await result
227
231
 
228
232
  async def get_response(self) -> Response:
229
233
  headers = {
230
- 'upgrade': 'websocket',
231
- 'connection': 'upgrade',
232
- 'sec-websocket-accept': base64.b64encode(hashlib.sha1(f'{self.websocket.key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11'.encode('utf-8')).digest()).decode('utf-8')
234
+ 'Upgrade': 'websocket',
235
+ 'Connection': 'Upgrade',
236
+ 'Sec-WebSocket-Accept': base64.b64encode(hashlib.sha1(f'{self.websocket.key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11'.encode('utf-8')).digest()).decode('utf-8')
233
237
  }
234
238
  if self.websocket.subprotocols:
235
239
  subprotocol = await self.websocket.on_subprotocol(self.websocket.subprotocols)
236
240
  if subprotocol:
237
241
  self.websocket._subprotocol = subprotocol
238
- headers['sec-websocket-protocol'] = subprotocol
242
+ headers['Sec-WebSocket-Protocol'] = subprotocol
239
243
  response = self.app.ResponseProxy_Class(self.app, Response(status = 101, headers = headers)).response
240
244
  response._proxy.websocket = self.websocket
241
245
  return response
@@ -244,7 +248,7 @@ class WebsocketProxy:
244
248
  Websocket.connectors.setdefault(self.websocket.request.path, []).append(self.websocket)
245
249
  if self.app.sync_server_url and self.websocket.request.path not in static.websocket_sync_server:
246
250
  static.websocket_sync_server[self.websocket.request.path] = redis.asyncio.Redis.from_url(self.app.sync_server_url, socket_timeout = self.app.sync_server_timeout, socket_connect_timeout = self.app.sync_server_timeout)
247
- asyncio.create_task(self.sync_server_running())
251
+ WebsocketProxy._sync_tasks[self.websocket.request.path] = asyncio.create_task(self.sync_server_running())
248
252
 
249
253
  loop = asyncio.get_running_loop()
250
254
  self.reader = asyncio.StreamReader()
@@ -259,10 +263,18 @@ class WebsocketProxy:
259
263
  await self.websocket.on_connect()
260
264
 
261
265
  async def sync_server_running(self):
266
+ pubsub = None
262
267
  try:
263
268
  if self.app.sync_server_url.startswith('redis'):
264
269
  while True:
265
270
  try:
271
+ if pubsub is not None:
272
+ try:
273
+ await pubsub.aclose()
274
+ except Exception:
275
+ pass
276
+ pubsub = None
277
+
266
278
  pubsub = redis.asyncio.from_url(self.app.sync_server_url, socket_timeout = None, socket_connect_timeout = None).pubsub()
267
279
  await pubsub.subscribe(self.websocket.request.path)
268
280
  async for message in pubsub.listen():
@@ -302,6 +314,13 @@ class WebsocketProxy:
302
314
  await asyncio.sleep(self.app.sync_server_timeout)
303
315
  except (KeyboardInterrupt, SystemExit, asyncio.CancelledError):
304
316
  ...
317
+ finally:
318
+ WebsocketProxy._sync_tasks.pop(self.websocket.request.path, None)
319
+ if pubsub is not None:
320
+ try:
321
+ await pubsub.aclose()
322
+ except Exception:
323
+ pass
305
324
 
306
325
  async def message(self):
307
326
  while True:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: CheeseAPI
3
- Version: 2.0.8b5
3
+ Version: 2.0.8b7
4
4
  Summary: 一款web协程框架
5
5
  Project-URL: Source, https://github.com/CheeseUnknown/CheeseAPI
6
6
  Author-email: Cheese Unknown <cheese@cheese.ren>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "CheeseAPI"
7
- version = "2.0.8-beta.5"
7
+ version = "2.0.8-beta.7"
8
8
  description = "一款web协程框架"
9
9
  readme = "README.md"
10
10
  license-files = { paths = [ "LICENSE" ] }
File without changes
File without changes
File without changes