- Introduced WS_Message_V3 standardized Pydantic model and WS_Manager_V3. - Implemented /v3/ws/ endpoint with granular Redis routing to solve "noisy neighbor" scaling issues. - Added presence tracking using Redis Sets for group coordination. - Comprehensive test suite added (unit and integration) covering models, manager, and routing logic. - Documentation: Created V3 Frontend WebSocket Guide and Project design spec. - Updated main Frontend API guide and tests README with new standards.
4.2 KiB
Aether API V3 WebSocket Integration Guide
This guide explains how to implement real-time communication using the Aether API V3 WebSocket protocol. V3 introduces granular routing, strict message schemas, and improved multi-tenant isolation compared to previous versions.
1. Key Improvements (V2 vs V3)
| Feature | WebSocket V2 (Legacy) | WebSocket V3 (Modern) |
|---|---|---|
| URL Prefix | /ws/ or /ws_redis/ |
/v3/ws/ |
| Routing | Global: Every client receives every message. | Granular: Redis filters messages before sending. |
| Performance | Low efficiency at scale (Python filtering). | High efficiency (Redis native pub/sub). |
| Schema | Loose JSON objects. | Strict Pydantic-validated models. |
| Presence | None / Manual. | Automatic Redis-backed presence sets. |
2. Connection Strategy
A. Endpoint URL
The V3 WebSocket path requires both a group_id and a client_id (using Vision ID random strings).
ws://[api_domain]/v3/ws/group/{group_id}/client/{client_id}
B. Connection Example (TypeScript)
const group_id = "group_abc123"; // Random ID
const client_id = "device_xyz789"; // Random ID
const ws_url = `ws://api.oneskyit.com/v3/ws/group/${group_id}/client/${client_id}`;
const socket = new WebSocket(ws_url);
socket.onopen = () => {
console.log("Connected to Aether WS V3");
};
3. The V3 Message Schema
All messages sent and received over V3 must follow the standardized WS_Message_V3 structure.
Message Fields
| Field | Type | Required | Description |
|---|---|---|---|
version |
string | Auto | Always "3". |
msg_type |
string | Yes | 'msg', 'cmd', 'heartbeat', 'presence' |
target |
string | Yes | 'direct', 'group', 'broadcast', 'echo' |
from_id |
string | No* | Client ID of sender (Auto-filled by server if omitted). |
to_id |
string | No | Target Client ID (Required for target: 'direct'). |
group_id |
string | No* | Target Group ID (Auto-filled by server if omitted). |
cmd |
string | No | Specific action keyword (e.g., 'RELOAD'). |
msg |
string | No | Human-readable text content. |
payload |
object | No | Flexible key-value data. |
sent_at |
string | Auto | ISO 8601 Timestamp. |
4. Message Targeting Logic
V3 uses the target field to determine which Redis channel to use, ensuring only the intended recipients receive the data.
A. Group Broadcast
Sends the message to every client connected to the same group_id.
{
"msg_type": "msg",
"target": "group",
"msg": "Hello team!"
}
B. Direct Message (DM)
Sends the message to one specific client ID, regardless of their group.
{
"msg_type": "msg",
"target": "direct",
"to_id": "target_client_random_id",
"msg": "Private message just for you."
}
C. System Broadcast
Sends the message to every connected client on the platform (use sparingly).
{
"msg_type": "cmd",
"target": "broadcast",
"cmd": "MAINTENANCE_WARNING"
}
D. Echo
Sends the message back only to the sender (useful for testing round-trip latency).
{
"msg_type": "msg",
"target": "echo",
"msg": "Ping!"
}
5. Specialized Message Types
Commands (cmd)
Used for remote control or orchestration.
{
"msg_type": "cmd",
"target": "group",
"cmd": "RELOAD_UI",
"payload": { "force": true }
}
Heartbeats (heartbeat)
Keep the connection alive and refresh presence in the backend. Should be sent every 30-60 seconds.
{
"msg_type": "heartbeat",
"target": "echo"
}
6. Migration Guide (V2 to V3)
If you are upgrading from the legacy V2 WebSocket (/ws/group/...):
- Change the URL: Prepend
/v3/to your WebSocket path. - Wrap your JSON: In V2, you might have sent
{"msg": "hi"}. In V3, this must be{"msg_type": "msg", "target": "group", "msg": "hi"}. - Use Vision IDs: Ensure all IDs passed in the path and
to_idfields are the random string IDs (id_random), not database integers. - Listen for
msg_type: Update your frontend handlers to switch logic based on themsg_typefield instead of proprietary keys.