WebSocket API¶
MAGK provides real-time data streaming over WebSocket connections. The data flow is:
TAK Clients → Python TAK Service → RabbitMQ (magk.cot fanout) → WebSocket Gateway → Browser
Connection Endpoints¶
| Path | Auth | Description |
|---|---|---|
ws(s)://domain/ws | Session cookie or ?token= | Authenticated WebSocket — full message stream |
ws(s)://domain/ws/public | None | Public read-only CoT stream |
Authenticated Connection¶
Connect with a session token via cookie or query parameter:
// Using session cookie (automatic in browsers)
const ws = new WebSocket('wss://magk.example.com/ws')
// Using explicit token
const ws = new WebSocket('wss://magk.example.com/ws?token=SESSION_TOKEN')
The server validates the session before upgrading the connection. Invalid or missing tokens result in the socket being destroyed without upgrade.
Public Connection¶
The public endpoint requires no authentication and provides a read-only CoT event stream:
const ws = new WebSocket('wss://magk.example.com/ws/public')
Public clients are auto-subscribed to the cot channel only.
Message Format¶
All WebSocket messages are JSON-encoded and follow a discriminated union pattern. Each message has a type field that determines the payload shape:
type WSMessage =
| WSCotMessage
| WSNodeStatusMessage
| WSScoreUpdateMessage
| WSEventStatusMessage
| WSMissionChangeMessage
| WSChatMessage
Every message includes a timestamp (ISO 8601) and an optional eventId to scope the message to a specific event.
Message Types¶
cot — Cursor on Target¶
Real-time position and status updates from TAK clients and sensors.
interface WSCotMessage {
type: 'cot'
payload: {
uid: string // Device unique ID (e.g. "ANDROID-a1b2c3d4")
type: string // CoT type (e.g. "a-f-G-U-C" for friendly ground unit)
how: string // How the position was determined (e.g. "m-g" for GPS)
time: string // Event time (ISO 8601)
start: string // Valid start time
stale: string // Stale time — marker disappears after this
lat: number // Latitude (WGS84)
lon: number // Longitude (WGS84)
hae: number // Height above ellipsoid (meters)
ce: number // Circular error (meters)
le: number // Linear error (meters)
detail?: unknown // Extended CoT detail fields
callsign?: string
affiliation?: 'friendly' | 'hostile' | 'neutral' | 'unknown'
}
timestamp: string
eventId?: string
}
node_status — MAGK Node Status¶
Status changes from MAGK Node hardware devices (battery, signal, online/offline).
interface WSNodeStatusMessage {
type: 'node_status'
payload: {
nodeId: string
name: string
status: 'online' | 'offline' | 'configuring' | 'error'
previousStatus?: string
batteryLevel?: number // 0–100
signalStrength?: number // dBm
lastSeen?: string // ISO 8601
}
timestamp: string
eventId?: string
}
Example:
{
"type": "node_status",
"payload": {
"nodeId": "550e8400-e29b-41d4-a716-446655440000",
"name": "Objective Alpha",
"status": "online",
"previousStatus": "configuring",
"batteryLevel": 87,
"signalStrength": -65
},
"timestamp": "2025-01-15T14:30:00.000Z",
"eventId": "660e8400-e29b-41d4-a716-446655440000"
}
score_update — Score Change¶
Score updates when a team captures an objective, scores a point, or the leaderboard changes.
interface WSScoreUpdateMessage {
type: 'score_update'
payload: {
groupId: string
groupName: string
eventId: string
points: number
objectivesCaptured: number
objectivesDefended: number
eliminations: number
}
timestamp: string
eventId?: string
}
Example:
{
"type": "score_update",
"payload": {
"groupId": "770e8400-e29b-41d4-a716-446655440000",
"groupName": "Blue Platoon",
"eventId": "660e8400-e29b-41d4-a716-446655440000",
"points": 1500,
"objectivesCaptured": 3,
"objectivesDefended": 1,
"eliminations": 12
},
"timestamp": "2025-01-15T14:35:00.000Z"
}
event_status — Event Lifecycle¶
Notifications when an event transitions between lifecycle states.
interface WSEventStatusMessage {
type: 'event_status'
payload: {
eventId: string
eventName: string
status: 'draft' | 'active' | 'paused' | 'completed' | 'archived'
previousStatus?: string
}
timestamp: string
eventId?: string
}
Example:
{
"type": "event_status",
"payload": {
"eventId": "660e8400-e29b-41d4-a716-446655440000",
"eventName": "Operation Nightfall",
"status": "active",
"previousStatus": "draft"
},
"timestamp": "2025-01-15T14:00:00.000Z"
}
mission_change — Mission Updates¶
Notifications when mission content changes (data packages added, CoT markers updated).
interface WSMissionChangeMessage {
type: 'mission_change'
payload: {
missionId: string
missionName: string
changeType: string // e.g. "ADD_CONTENT", "REMOVE_CONTENT"
contentUid?: string
creatorUid?: string
}
timestamp: string
}
chat — Chat Messages¶
Real-time chat messages within event chatrooms.
interface WSChatMessage {
type: 'chat'
payload: {
id: string
chatroomId: string
senderCallsign: string
message: string
latitude: number | null
longitude: number | null
createdAt: string
}
timestamp: string
}
Client Usage Example¶
const ws = new WebSocket('wss://magk.example.com/ws')
ws.onopen = () => {
console.log('Connected to MAGK WebSocket')
}
ws.onmessage = (event) => {
const msg: WSMessage = JSON.parse(event.data)
switch (msg.type) {
case 'cot':
// Update map marker position
updateMarker(msg.payload)
break
case 'node_status':
// Update node status indicator
updateNodeStatus(msg.payload)
break
case 'score_update':
// Refresh scoreboard
updateScoreboard(msg.payload)
break
case 'event_status':
// Handle event lifecycle change
handleEventChange(msg.payload)
break
case 'mission_change':
// Sync mission content
syncMission(msg.payload)
break
case 'chat':
// Display chat message
displayChat(msg.payload)
break
}
}
ws.onclose = (event) => {
console.log(`Disconnected: ${event.code} ${event.reason}`)
// Implement reconnection logic
}
Reconnection¶
The MAGK web client uses automatic reconnection with exponential backoff. If the WebSocket connection drops, the client retries with increasing delays (1s, 2s, 4s, 8s, up to 30s max). The useCoTStream hook handles this automatically for the tactical map.