Hello World in TypeScript
The HDDS TypeScript SDK provides native FFI bindings to the hdds-c shared library via koffi. No WebSocket bridge needed -- your application communicates directly over UDP multicast using the RTPS protocol.
Time: ~10 minutes Prerequisites: Node.js >= 18, hdds-c shared library built
Step 1: Build hdds-c
The TypeScript SDK calls the native HDDS library directly. Build it first:
# From the HDDS repository root
git clone https://git.hdds.io/hdds/hdds.git
cd hdds
cargo build --release -p hdds-c
# The library will be at:
# Linux: target/release/libhdds_c.so
# macOS: target/release/libhdds_c.dylib
# Windows: target/release/hdds_c.dll
Step 2: Install the SDK
cd sdk/typescript
npm install
If the native library is not in target/release/ or system paths, set:
export HDDS_LIB_PATH=/path/to/directory/containing/libhdds_c.so
Step 3: Create the Publisher
Create publisher.ts:
import { Participant, QoS, TransportMode } from "@hdds/client";
interface Temperature {
sensor_id: string;
value: number;
timestamp: number;
}
function main(): void {
// Create a participant on the default domain (UDP multicast)
const participant = Participant.create("ts_publisher");
// Reliable QoS with history for late joiners
const qos = QoS.reliable().transientLocal().historyDepth(10);
const writer = participant.createWriter<Temperature>("temperature", qos);
console.log("Publishing temperature readings...");
for (let i = 0; i < 10; i++) {
const temp: Temperature = {
sensor_id: "sensor-001",
value: 22.0 + i * 0.5,
timestamp: Date.now(),
};
writer.writeJson(temp);
console.log(`Published: sensor=${temp.sensor_id}, temp=${temp.value}C`);
}
// Clean up
qos.dispose();
participant.dispose();
}
main();
writeJson() and takeJson() use JSON encoding, which is not CDR-compatible.
This works for TypeScript-to-TypeScript communication. For cross-language interop
with C/C++/Python, use write() with CDR2-encoded buffers.
Step 4: Create the Subscriber
Create subscriber.ts:
import { Participant, QoS, WaitSet } from "@hdds/client";
interface Temperature {
sensor_id: string;
value: number;
timestamp: number;
}
function main(): void {
const participant = Participant.create("ts_subscriber");
const qos = QoS.reliable().transientLocal().historyDepth(10);
const reader = participant.createReader<Temperature>("temperature", qos);
// Use a WaitSet to block until data arrives
const waitset = new WaitSet();
waitset.attachReader(reader);
console.log("Waiting for temperature data...");
while (true) {
if (waitset.wait(5.0)) {
const sample = reader.takeJson<Temperature>();
if (sample !== null) {
console.log(
`Received: sensor=${sample.sensor_id}, temp=${sample.value}C`
);
}
} else {
console.log("No data received in 5 seconds, stopping.");
break;
}
}
// Clean up
waitset.dispose();
qos.dispose();
participant.dispose();
}
main();
Step 5: Run
Open two terminals:
# Terminal 1
cd sdk/typescript
npx ts-node subscriber.ts
# Terminal 2
cd sdk/typescript
npx ts-node publisher.ts
Single-File Example (Intra-Process)
For a quick test without networking, you can publish and subscribe in the same
process using INTRA_PROCESS transport:
import { Participant, QoS, WaitSet, TransportMode } from "@hdds/client";
interface HelloMessage {
message: string;
count: number;
timestamp: number;
}
const participant = Participant.create("ts_hello_world", {
transport: TransportMode.INTRA_PROCESS,
});
const qos = QoS.reliable().transientLocal().historyDepth(10);
const writer = participant.createWriter<HelloMessage>("hello_world", qos);
const reader = participant.createReader<HelloMessage>("hello_world", qos.clone());
const waitset = new WaitSet();
waitset.attachReader(reader);
for (let i = 1; i <= 5; i++) {
writer.writeJson({ message: "Hello from TypeScript!", count: i, timestamp: Date.now() });
if (waitset.wait(1.0)) {
const received = reader.takeJson<HelloMessage>();
if (received !== null) {
console.log(`${received.message} (count: ${received.count})`);
}
}
}
waitset.dispose();
qos.dispose();
participant.dispose();
QoS Configuration
The SDK provides a fluent builder API for QoS:
import { QoS } from "@hdds/client";
// Reliable with deadline and partitioning
const qos = QoS.reliable()
.transientLocal()
.historyDepth(10)
.deadlineMs(500)
.partition("sensor_data")
.livelinessAutomatic(5.0);
// Inspect QoS settings
console.log(qos.isReliable()); // true
console.log(qos.getHistoryDepth()); // 10
console.log(qos.toString()); // "QoS(reliable, transient_local, depth=10)"
// Clone for reuse (writer and reader need separate instances)
const readerQos = qos.clone();
// RTI Connext compatible defaults
const rtiQos = QoS.rtiDefaults();
Error Handling
All operations throw HddsError on failure:
import { HddsError, HddsErrorCode, Participant } from "@hdds/client";
try {
const p = Participant.create("test");
} catch (e) {
if (e instanceof HddsError) {
console.error(`HDDS error [${e.code}]: ${e.message}`);
}
}
Architecture
Node.js Application
|
| @hdds/client (koffi FFI)
v
+----------------+
| libhdds_c | Native shared library
+----------------+
|
| UDP Multicast / RTPS
v
+----------------+
| DDS Domain | Other DDS peers (any vendor)
+----------------+
The SDK loads the hdds-c shared library at runtime and calls C functions directly. No intermediate bridge process is needed.
The native FFI SDK is Node.js only. For browser applications, use the hdds-ws WebSocket bridge instead.
What's Next?
- QoS Policies -- Fine-tune data distribution
- TypeScript SDK README -- Full API reference
- Examples -- More complex examples