forge/bin/icom/README.md
Jacob Schmidt ebfe77a340 feat: implement complete Forge framework with Rust/Redis backend and Arma 3 integration
Implemented features:
- High-performance Rust extension with Redis persistence
- Actor/player management with loadout, position, and state tracking
- Banking system with deposit, withdraw, and transfer operations
- Physical and virtual garage/locker systems for vehicle and equipment storage
- Organization management with member tracking and permissions
- Client-side UI with React-like state management
- Server-side event-driven architecture with CBA Events
- Security: Self-transfer prevention at multiple layers
- Logging system with per-module log files
- ICOM module for inter-server communication

Co-Authored-By: Warp <agent@warp.dev>
2026-01-04 12:52:15 -06:00

10 KiB

Forge ICOM Server (Internal Communication)

A standalone TCP server for inter-Arma3-server communication. ICOM enables multiple Arma 3 servers to communicate with each other, facilitating cross-server events like mission spawning, supply drops, and military reports.

Architecture

[Arma Server 1] <---> [Forge ICOM] <---> [Arma Server 2]
   (Extension)         (TCP 9090)           (Extension)
      Client                                    Client

Each Arma server's extension connects to the ICOM server as a client. ICOM routes messages between servers based on target IDs or broadcasts to all connected servers.

Configuration

The ICOM server can be configured using a config.toml file. Create one from the example:

cp bin/icom/config.example.toml config.toml

Place config.toml in the same directory as the forge-icom executable or in the current working directory.

Configuration Options

[server]
# Host to bind to
# "0.0.0.0" = All interfaces (allows remote connections)
# "127.0.0.1" = Localhost only
host = "0.0.0.0"

# Port to listen on
port = 9090

Defaults: If no config file is found, defaults to 0.0.0.0:9090.

Building

# Build release binary
cargo build --release -p forge-icom

# The executable will be at:
# target/release/forge-icom.exe (Windows)

Running

# Run the ICOM server
./target/release/forge-icom.exe

# Or during development
cargo run -p forge-icom

The server will listen on 0.0.0.0:9090 by default.

Design Philosophy

Generic Event System

ICOM uses a generic event-based architecture instead of predefined message types. This means:

  • Flexibility: Add new event types without changing the ICOM server code
  • Simplicity: Only one Event message type instead of multiple specialized types
  • Decoupled: ICOM doesn't need to know about your game logic
  • Future-proof: Easy to extend as your needs evolve

ICOM simply routes events between servers - your application logic determines what each event means.

Message Protocol

All messages are JSON objects sent as newline-delimited strings. Each message has a type field that determines its structure.

Register

First message from each Arma server to identify itself:

{
  "type": "register",
  "server_id": "server_1"
}

Response:

{
  "type": "registered",
  "session_id": "uuid-here"
}

Event (Send to Specific Server)

Send an event with arbitrary JSON data to a specific server:

{
  "type": "event",
  "target_server": "server_2",
  "event_name": "supply_drop",
  "data": {
    "coords": [1234.5, 5678.9, 0.0],
    "supplies": ["ammo_box", "medical_supplies"]
  }
}

Another example:

{
  "type": "event",
  "target_server": "server_2",
  "event_name": "spawn_mission",
  "data": {
    "mission_type": "convoy_ambush",
    "difficulty": "hard",
    "location": [1234, 5678, 0]
  }
}

Broadcast

Send event to all connected servers (except sender):

{
  "type": "broadcast",
  "event_name": "global_alert",
  "data": {
    "message": "Nuclear strike incoming!",
    "severity": "critical"
  }
}

Acknowledgment

Response to successful message delivery:

{
  "type": "ack",
  "message_id": null,
  "success": true,
  "error": null
}

Error response:

{
  "type": "ack",
  "message_id": null,
  "success": false,
  "error": "Target server 'server_3' not found"
}

Integration with Arma Extension

Client Library

The forge-icom crate includes a client module that provides a high-level API for connecting to ICOM:

use forge_icom::client::IComClient;
use forge_icom::Message;
use serde_json::json;

// Connect and register (automatically handles registration)
let client = IComClient::connect("127.0.0.1:9090", "server_1".to_string()).await?;

// Send event to another server
client.send_event(
    "server_2",
    "supply_drop",
    json!({
        "coords": [1234.5, 5678.9, 0.0],
        "supplies": ["ammo", "medical"]
    })
).await?;

// Broadcast to all servers
client.broadcast(
    "global_alert",
    json!({"message": "Server restart in 5 minutes"})
).await?;

// Listen for incoming events
client.listen_for_events(|msg| {
    match msg {
        Message::Event { event_name, data, .. } => {
            // Forward to Arma via callback
        }
        _ => {}
    }
    Ok(())
}).await?;

Extension Integration

The Forge server extension includes full ICOM integration:

  1. Initialization: Connects to ICOM on extension startup (or manually via icom:connect)
  2. Event Listener: Spawns background task to receive events continuously
  3. Callback System: Forwards events to Arma via CBA event handlers
  4. Extension Commands: Provides SQF commands to send/receive events

Important Notes:

  • The extension uses try_read() to avoid deadlocks when accessing context from async tasks
  • Broadcast events are not sent back to the originating server
  • Connection can be initiated manually if automatic startup connection fails

SQF Usage

Connecting to ICOM

// Connect manually (if not using automatic startup connection)
private _result = "forge_server" callExtension ["icom:connect", ["127.0.0.1:9090", "server_1"]];
systemChat _result; // "Connection initiated" or "ERROR: Already connected"

Sending Events

// Send event to specific server
private _data = createHashMapFromArray [
    ["coords", [1234, 5678, 0]],
    ["supplies", ["ammo_box", "medical_supplies"]]
];
"forge_server" callExtension ["icom:send_event", ["server_2", "supply_drop", (toJSON _data)]];

// Spawn mission on another server
private _missionData = createHashMapFromArray [
    ["mission_type", "convoy_ambush"],
    ["difficulty", "hard"],
    ["location", [1234, 5678, 0]]
];
"forge_server" callExtension ["icom:send_event", ["server_2", "spawn_mission", (toJSON _missionData)]];

// Broadcast to all servers (except sender)
private _alertData = createHashMapFromArray [
    ["message", "Nuclear strike incoming!"],
    ["severity", "critical"]
];
"forge_server" callExtension ["icom:broadcast", ["global_alert", (toJSON _alertData)]];

Receiving Events

Handle incoming events with a CBA event handler:

["forge_icom_event", {
    params ["_eventName", "_data"];

    switch (_eventName) do {
        case "supply_drop": {
            private _coords = _data get "coords";
            private _supplies = _data get "supplies";
            // Create supply drop at coordinates
            [_coords, _supplies] call YourMod_fnc_createSupplyDrop;
        };
        case "spawn_mission": {
            private _missionType = _data get "mission_type";
            private _location = _data get "location";
            // Spawn the mission
            [_missionType, _location] call YourMod_fnc_spawnMission;
        };
        case "global_alert": {
            private _message = _data get "message";
            // Show alert to all players
            [_message] remoteExec ["hint", 0];
        };
        default {
            diag_log format ["[ICOM] Unhandled event: %1", _eventName];
        };
    };
}] call CBA_fnc_addEventHandler;

Production Deployment

As Windows Service

You can run ICOM as a Windows service using tools like NSSM:

# Install NSSM
winget install NSSM.NSSM

# Create service
nssm install ForgeICOM "C:\path\to\forge-icom.exe"
nssm start ForgeICOM

Docker (for Linux servers)

FROM rust:1.70 as builder
WORKDIR /app
COPY . .
RUN cargo build --release -p forge-icom

FROM debian:bookworm-slim
COPY --from=builder /app/target/release/forge-icom /usr/local/bin/
EXPOSE 9090
CMD ["forge-icom"]
docker build -t forge-icom .
docker run -d -p 9090:9090 --name forge-icom forge-icom

Features

  • Async I/O: Non-blocking message handling using Tokio
  • Multiple connections: Handle dozens of Arma servers simultaneously
  • Generic event system: Send arbitrary JSON data without predefined message types
  • Message routing: Direct events to specific servers or broadcast to all
  • Session management: Track connected servers with UUIDs
  • Duplicate connection handling: Automatically replaces old connections when server reconnects
  • Automatic cleanup: Remove disconnected servers from registry
  • Graceful error handling: Clients continue running even when target servers are offline

Testing

Running Examples

# Terminal 1: Start ICOM server
cargo run --bin forge-icom

# Terminal 2: Start server_1 (listener)
cargo run --example server_1_client

# Terminal 3: Start server_2 (sender)
cargo run --example server_2_client

You should see events flow from server_2 → ICOM → server_1.

Test with Extension

  1. Start ICOM server
  2. Start Arma 3 server with Forge extension
  3. In Arma, connect manually (if needed):
    "forge_server" callExtension ["icom:connect", ["127.0.0.1:9090", "server_1"]]
    
  4. Set up CBA event handler in mission init:
    ["forge_icom_event", {
        params ["_eventName", "_data"];
        systemChat format ["ICOM Event: %1", _eventName];
    }] call CBA_fnc_addEventHandler;
    
  5. Run example sender client to test event reception:
    cargo run --example server_2_client
    
  6. Check logs at @forge_server/logs/icom.log to verify events are received

Next Steps

  1. Run the examples to see the system in action
  2. Add CBA event handler in your mission to process forge_icom_event
  3. Define your event types (supply_drop, spawn_mission, etc.) based on your needs
  4. Test with multiple Arma servers locally
  5. Deploy ICOM server to production (Windows Service or Docker)
  6. Configure server IDs in extension config for each server

Monitoring

The ICOM server logs all important events to stdout:

  • 🔥 Server startup
  • 📡 New connections
  • Server registrations
  • 📢 Broadcast messages
  • 📨 Message forwarding
  • 🗑️ Server disconnections
  • Errors

Consider redirecting output to a file or logging service for production.