Message Propagation in DroneEngage Communication Server

This document describes the message routing and propagation logic in the server-to-server mesh relay system.

Architecture Overview

                    ┌─────────────────────┐
                    │    Super Server     │
                    │  (ParentCommServer) │
                    └──────────┬──────────┘
                               │
              ┌────────────────┼────────────────┐
              │                │                │
              ▼                ▼                ▼
       ┌────────────┐   ┌────────────┐   ┌────────────┐
       │  Child A   │   │  Child B   │   │  Child C   │
       │(ChildComm) │   │(ChildComm) │   │(ChildComm) │
       └─────┬──────┘   └─────┬──────┘   └─────┬──────┘
             │                │                │
        Local Units      Local Units      Local Units
        (WS Clients)     (WS Clients)     (WS Clients)

Key Components

Files

| File | Role | |——|——| | server/chat_server/js_andruav_chat_server.js | Main message routing logic | | server/server_to_server/js_parent_comm_server.js | Super server - accepts child connections | | server/server_to_server/js_child_comm_server.js | Child server - connects to parent |

Core Functions

| Function | Location | Purpose | |———-|———-|———| | fn_parseMessage() | chat_server | Handles messages from local WebSocket clients | | fn_parseExternalMessage() | chat_server | Handles messages from relay servers | | forwardMessage() | chat_server | Forwards messages to parent/child relay servers | | getServerOriginID() | chat_server | Returns unique server ID for loop prevention |


Data Flow

1. Local Client → Relay Propagation

When a local WebSocket client sends a message:

Local Client (WS)
       │
       ▼
fn_parseMessage()
       │
       ├──► Local delivery (fn_sendToAll*, fn_sendToIndividual)
       │
       └──► forwardMessage()
                 │
                 ├──► Parent Server (if enable_super_server=true)
                 │
                 └──► Child Servers (if enable_persistant_relay=true)

Code path:

  1. fn_onWsMessage() receives WS message

  2. Calls fn_parseMessage(p_ws, p_message, p_isBinary)

  3. Parses JSON, injects permission (p field)

  4. Routes to local clients based on ty (routing type) and tg (target)

  5. Calls forwardMessage() to propagate to relay servers

2. External Server → Local Delivery Only

When a message arrives from a relay server (parent or child):

Relay Server
       │
       ▼
fn_parseExternalMessage()
       │
       └──► Local delivery ONLY (fn_sendToAll*, fn_sendToIndividual)
       
       ✗ NO re-forwarding to other servers

Code path:

  1. ParentCommServer.on('message') or ChildCommServer.onReceive()

  2. Calls fn_parseExternalMessage(p_message, p_isBinary)

  3. Checks _path array for loop prevention

  4. Routes to local clients only

  5. Does NOT call forwardMessage() - prevents infinite loops


Loop Prevention Mechanism

Path Tracking

Each server has a unique server_id defined in config:

function getServerOriginID() {
    return global.m_serverconfig?.m_configuration?.server_id || 'unknown';
}

Injection Point

In forwardMessage(), the server ID is appended to the _path array:

if (!Array.isArray(v_jmsg._path)) v_jmsg._path = [];
v_jmsg._path.push(getServerOriginID());

Check Point

In fn_parseExternalMessage(), messages that have already passed through this server are dropped:

if (Array.isArray(v_jmsg._path) && v_jmsg._path.includes(getServerOriginID())) {
    return;  // Ignore - this message already passed through us
}

Why This Matters

When ParentCommServer.forwardMessage() broadcasts to all children, it includes the originating child. Without path tracking:

Child A sends message → Parent → broadcasts to [A, B, C]
                                        │
                                        └─► Child A receives its own message back!

With _path check, Child A ignores the bounce-back because its ID is already in the path array.


Message Routing Types

The ty field determines routing behavior:

| Value | Constant | Behavior | |——-|———-|———-| | 'g' | CONST_WS_MSG_ROUTING_GROUP | Broadcast to group | | 'i' | CONST_WS_MSG_ROUTING_INDIVIDUAL | Targeted delivery | | 's' | CONST_WS_MSG_ROUTING_SYSTEM | System commands (local only) |

Target Field (tg) Special Values

| Value | Constant | Meaning | |——-|———-|———| | '_GCS_' | CONST_WS_SENDER_ALL_GCS | All GCS units | | '_GD_' | CONST_WS_SENDER_ALL | All units (GCS + Agents) | | '_AGN_' | CONST_WS_SENDER_ALL_AGENTS | All drone agents | | (other) | - | Specific unit ID (one-to-one) |


Configuration Flags

In server config file:

| Flag | Effect | |——|——–| | enable_super_server: true | This server acts as a parent (accepts child connections) | | enable_persistant_relay: true | This server connects to a parent as a child | | server_id | Unique identifier for loop prevention | | s2s_ws_target_ip / s2s_ws_target_port | Parent server address (for child mode) |


Summary Table

| Message Source | Handler | Local Delivery | Relay Forward | Loop Check | |—————-|———|—————-|—————|————| | Local WS Client | fn_parseMessage() | ✅ | ✅ | Appends to _path | | Parent Server | fn_parseExternalMessage() | ✅ | ❌ | Checks _path | | Child Server | fn_parseExternalMessage() | ✅ | ❌ | Checks _path |