Architecture overview ===================== At a lower level, request and message flow looks like this: :: ASGI → Channels → Engine.IO transport consumers → Engine.IO core → Socket.IO → your handlers Conceptually, this matches the Node.js reference layering: :: Your code ↔ Socket.IO ↔ Engine.IO ↔ raw HTTP/WS Transport flow -------------- Concretely: * the ASGI server, such as Daphne or Uvicorn, receives HTTP/WebSocket connections; * Django Channels routes them to ``SocketIOConsumer.as_asgi()``; * the consumer dispatches HTTP scopes to the Engine.IO long-polling transport; * the consumer dispatches WebSocket scopes to the Engine.IO WebSocket transport; * the Engine.IO core handles query parameters such as ``EIO=4`` and ``transport=...``; * Engine.IO handles heartbeats, HTTP payload framing, WebSocket frames, and per-connection session state; * completed Engine.IO ``message`` packets are passed to the Socket.IO layer; * Socket.IO parses packets and calls your consumer event handlers. Engine.IO layer --------------- The Engine.IO implementation lives in ``sio.engineio`` and provides: ``EngineIOSession`` Per-connection state, including transport, queues, and heartbeats. ``LongPollingConsumer`` Channels ``AsyncHttpConsumer`` implementing the HTTP long-polling transport. ``EngineIOWebSocketConsumer`` Channels ``AsyncWebsocketConsumer`` for the WebSocket transport and upgrade. ``EngineIOSocket`` Application-facing wrapper around a session, used by Socket.IO. ``sio.engineio.packets`` Helpers to encode and decode Engine.IO packets and HTTP payloads. Each Engine.IO connection is represented by one ``EngineIOSession`` and one ``EngineIOSocket``. The polling and WebSocket transports share the same session. Socket.IO layer --------------- The Socket.IO implementation lives in ``sio.socketio`` and provides: ``SocketIOPacket`` In-memory packet representation, including type, namespace, and data. ``SocketIOParser`` Converts Engine.IO ``message`` payloads into Socket.IO packets, including binary attachment handling and placeholder substitution. ``SocketIOServer`` Manages namespaces, per-namespace sockets, room membership, and broadcasts. ``NamespaceSocket`` Represents one client in one namespace and exposes methods such as ``emit``, ``send``, ``join``, ``leave``, ``leave_all``, and ``disconnect``. The server is configured once and used by all consumers. The singleton helper ``sio.socketio.server.get_socketio_server`` installs ``SocketIOServer`` as the Engine.IO application handler through ``set_engineio_app``. Consumer integration -------------------- ``sio.SocketIOConsumer`` glues everything together: * it creates and configures the global ``SocketIOServer`` on first use; * for each subclass, it registers a namespace; * it wires ``connect`` and ``disconnect`` methods if present; * it maps methods named ``event_`` to Socket.IO events named ````; * it exposes ``as_asgi()``, which returns an ASGI app that routes HTTP scopes to ``LongPollingConsumer`` and WebSocket scopes to ``EngineIOWebSocketConsumer``. You typically never touch the lower-level Engine.IO consumers directly. Mount your ``SocketIOConsumer`` subclass in Channels routing.