django: a context bundle over the socket
The socket carried rpc but not ctx, so a socket transport could not fetch a context and every app needed an HTTP connection beside it. Dispatches through the same execute_context the HTTP view calls; that view's origin-side cache is a CDN concern with nothing in front of a socket, so it is not on this path. Both backends now answer subscribe/unsubscribe/message/rpc/ctx on one envelope. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ Protocol:
|
||||
|
||||
# RPC calls (server functions)
|
||||
{"action": "rpc", "id": "request-id", "fn": "function_name", "args": {...}}
|
||||
{"action": "ctx", "id": "request-id", "context": "name", "params": {...}}
|
||||
|
||||
Server sends:
|
||||
# Channel messages
|
||||
@@ -167,6 +168,8 @@ class DjangoReactConsumer(AsyncJsonWebsocketConsumer):
|
||||
await self._handle_message(content)
|
||||
elif action == "rpc":
|
||||
await self._handle_rpc(content)
|
||||
elif action == "ctx":
|
||||
await self._handle_ctx(content)
|
||||
else:
|
||||
await self.send_json(
|
||||
{
|
||||
@@ -503,6 +506,61 @@ class DjangoReactConsumer(AsyncJsonWebsocketConsumer):
|
||||
|
||||
await self.send_json({"id": request_id, "ok": True, "data": data})
|
||||
|
||||
async def _handle_ctx(self, content: dict):
|
||||
"""
|
||||
Handle a context-bundle fetch.
|
||||
|
||||
Protocol:
|
||||
Request: {"action": "ctx", "id": "request-id", "context": "name", "params": {...}}
|
||||
Response: {"id": "request-id", "ok": true, "data": {fn_name: result, ...}}
|
||||
or: {"id": "request-id", "ok": false, "error": {...}}
|
||||
|
||||
Dispatches through the same execute_context the HTTP view calls. That view's
|
||||
origin-side cache is a CDN concern with nothing in front of a socket, so it is not
|
||||
part of this path.
|
||||
"""
|
||||
from mizan.client.executor import execute_context, FunctionError
|
||||
|
||||
request_id = content.get("id")
|
||||
context_name = content.get("context")
|
||||
|
||||
if not request_id:
|
||||
await self.send_json({"error": "ctx request missing 'id' field"})
|
||||
return
|
||||
|
||||
if not context_name:
|
||||
await self.send_json(
|
||||
{
|
||||
"id": request_id,
|
||||
"ok": False,
|
||||
"error": {"code": "BAD_REQUEST", "message": "Missing 'context' field"},
|
||||
}
|
||||
)
|
||||
return
|
||||
|
||||
ws_request = WebSocketRequest(
|
||||
self.scope, channel_name=getattr(self, "channel_name", None)
|
||||
)
|
||||
result = await sync_to_async(execute_context, thread_sensitive=True)(
|
||||
ws_request, context_name, content.get("params") or {}
|
||||
)
|
||||
|
||||
if isinstance(result, FunctionError):
|
||||
await self.send_json(
|
||||
{
|
||||
"id": request_id,
|
||||
"ok": False,
|
||||
"error": {
|
||||
"code": result.code.value,
|
||||
"message": result.message,
|
||||
**({"details": result.details} if result.details else {}),
|
||||
},
|
||||
}
|
||||
)
|
||||
return
|
||||
|
||||
await self.send_json({"id": request_id, "ok": True, "data": result.data})
|
||||
|
||||
async def channel_message(self, event: dict):
|
||||
"""
|
||||
Handle messages broadcast to a group.
|
||||
|
||||
Reference in New Issue
Block a user