Skip to content

Latest commit

 

History

History
1164 lines (807 loc) · 24.1 KB

File metadata and controls

1164 lines (807 loc) · 24.1 KB

HuiNet API Reference

Complete API reference for HuiNet - A decentralized Agent-to-Agent (A2A) networking library with P2P communication.

Table of Contents


Core Classes

HuiNet

The main P2P network node class that provides decentralized networking capabilities for Agents.

Extends: EventEmitter

Example

import { HuiNet } from '@huinet/network';

const huinet = new HuiNet({
  listenPort: 8000,
  enableMDNS: true
});

await huinet.start();

HuiNetNode

Alias for HuiNet class, providing clearer naming conventions for Agent integration.

Note: HuiNetNode is an alias of HuiNet and can be used interchangeably.

Example

import { HuiNetNode } from '@huinet/network';

const node = new HuiNetNode({
  listenPort: 8000
});

Configuration

HuiNetConfig

Configuration interface for initializing a HuiNet node.

interface HuiNetConfig {
  keyPair?: KeyPair;              // Optional: Cryptographic key pair (auto-generated if not provided)
  listenPort?: number;            // Optional: Port to listen on (default: 8000)
  listenHost?: string;            // Optional: Host address to bind to (default: '0.0.0.0')
  bootstrapNodes?: string[];      // Optional: Array of bootstrap node addresses (host:port format)
  maxCoreConnections?: number;    // Optional: Maximum number of core/persistent connections (default: 10)
  maxActiveConnections?: number;  // Optional: Maximum number of active cached connections (default: 50)
  enableMDNS?: boolean;           // Optional: Enable mDNS discovery (default: true)
  promoteToActiveThreshold?: number;  // Optional: Connections to promote to Active layer (default: 3)
  promoteToCoreThreshold?: number;    // Optional: Connections to promote to Core layer (default: 10)
  routingCleanupInterval?: number;    // Optional: Routing table cleanup interval in ms (default: 300000)
  maxNodeAge?: number;                // Optional: Maximum node age in ms before cleanup (default: 3600000)
}

Fields

  • keyPair (KeyPair, optional): Cryptographic key pair for node identity. If not provided, a new key pair will be generated automatically.
  • listenPort (number, optional): TCP port for incoming connections. Defaults to 8000.
  • listenHost (string, optional): Host address to bind the server to. Defaults to '0.0.0.0' (all interfaces).
  • bootstrapNodes (string[], optional): Array of bootstrap node addresses in 'host:port' format. The node will attempt to connect to these on startup.
  • maxCoreConnections (number, optional): Maximum number of persistent core connections to maintain. Defaults to 10.
  • maxActiveConnections (number, optional): Maximum number of active cached connections. Defaults to 50.
  • enableMDNS (boolean, optional): Whether to enable mDNS-based peer discovery. Defaults to true.
  • promoteToActiveThreshold (number, optional): Number of connections after which a node is auto-promoted to Active layer. Defaults to 3.
  • promoteToCoreThreshold (number, optional): Number of connections after which a node is auto-promoted to Core layer. Defaults to 10.
  • routingCleanupInterval (number, optional): Interval in milliseconds for routing table cleanup. Defaults to 300000 (5 minutes).
  • maxNodeAge (number, optional): Maximum age in milliseconds for a node before cleanup. Defaults to 3600000 (1 hour).

Example

import { HuiNet, generateKeyPair } from '@huinet/network';

// Basic configuration
const config1: HuiNetConfig = {
  listenPort: 9000,
  enableMDNS: true
};

// Advanced configuration with custom key pair
const keyPair = generateKeyPair();
const config2: HuiNetConfig = {
  keyPair: keyPair,
  listenPort: 8000,
  listenHost: '0.0.0.0',
  bootstrapNodes: [
    '192.168.1.100:8000',
    'example.com:9000'
  ],
  maxCoreConnections: 20,
  maxActiveConnections: 100,
  enableMDNS: true,
  // Routing table configuration
  promoteToActiveThreshold: 5,
  promoteToCoreThreshold: 15,
  routingCleanupInterval: 600000,  // 10 minutes
  maxNodeAge: 7200000               // 2 hours
};

const huinet = new HuiNet(config2);

Methods

start()

Start the HuiNet node, initializing the TCP server, mDNS discovery (if enabled), and connecting to bootstrap nodes.

async start(): Promise<void>

Behavior

  1. Starts the TCP server on the configured host and port
  2. Initializes mDNS discovery service if enableMDNS is true
  3. Attempts to connect to all configured bootstrap nodes
  4. Sets the node state to running
  5. Emits the ready event when complete

Example

const huinet = new HuiNet({ listenPort: 8000 });

huinet.on('ready', () => {
  console.log('Node is ready and listening');
});

await huinet.start();

stop()

Stop the HuiNet node, closing all connections and services.

async stop(): Promise<void>

Behavior

  1. Stops the TCP server
  2. Stops the mDNS discovery service
  3. Disconnects all client connections
  4. Clears the connection pool
  5. Sets the node state to stopped

Example

// Graceful shutdown
process.on('SIGINT', async () => {
  console.log('Shutting down...');
  await huinet.stop();
  process.exit(0);
});

send()

Send a message to a target node by NodeID.

async send(targetNodeID: string, message: any): Promise<void>

Parameters

  • targetNodeID (string): The NodeID of the recipient
  • message (any): Message data (any JSON-serializable object)

Throws

  • Error - If the target node is unknown (not in routing table)
  • Error - If connection to the target fails

Behavior

  1. Looks up the target node in the routing table
  2. Establishes a connection if not already connected
  3. Sends the message as JSON
  4. Automatically handles reconnection if needed

Example

// Send a simple message
await huinet.send(targetNodeID, {
  type: 'chat',
  text: 'Hello, World!'
});

// Send complex data
await huinet.send(targetNodeID, {
  type: 'file-transfer',
  filename: 'document.pdf',
  size: 1024000,
  data: base64EncodedData
});

connectToNode()

Manually connect to a node at a specific address.

async connectToNode(host: string, port: number, nodeID?: string): Promise<boolean>

Parameters

  • host (string): Target host address
  • port (number): Target port number
  • nodeID (string, optional): NodeID of the target (used for event tracking)

Returns

boolean - true if connection succeeded, false otherwise

Behavior

  1. Creates a new TCP client connection
  2. Sets up event handlers for the connection
  3. Adds the node to the routing table on success
  4. Emits peerConnected event on success
  5. Returns false on connection failure

Example

// Connect to a known node
const success = await huinet.connectToNode('192.168.1.100', 8000);

if (success) {
  console.log('Connected successfully');
} else {
  console.log('Connection failed');
}

// Connect with known NodeID
await huinet.connectToNode('example.com', 9000, 'QmXxx...');

// Handle connection events
huinet.on('peerConnected', (nodeID) => {
  console.log(`Connected to ${nodeID}`);
});

getNodeID()

Get the current node's ID.

getNodeID(): string

Returns

string - The NodeID (Base58-encoded SHA-256 hash of the public key)

Example

const nodeID = huinet.getNodeID();
console.log(`My NodeID: ${nodeID}`);

getPublicKey()

Get the current node's public key.

getPublicKey(): Buffer

Returns

Buffer - The node's public key (32 bytes)

Example

const publicKey = huinet.getPublicKey();
console.log(`Public Key: ${publicKey.toString('hex')}`);

getRoutingTable()

Get the routing table containing known nodes.

getRoutingTable(): RoutingTable

Returns

RoutingTable - The routing table object

Example

const routingTable = huinet.getRoutingTable();

// Get all known nodes
const allNodes = routingTable.getAllKnownNodes();

// Get a specific node
const node = routingTable.getKnownNode(nodeID);

if (node) {
  console.log(`Node state: ${node.state}`);
  console.log(`Addresses: ${node.addresses.length}`);
}

getConnectionPool()

Get the connection pool managing active connections.

getConnectionPool(): ConnectionPool

Returns

ConnectionPool - The connection pool object

Example

const pool = huinet.getConnectionPool();

// Get connection statistics
const stats = pool.getStats();
console.log(`Core connections: ${stats.coreCount}`);
console.log(`Active connections: ${stats.activeCount}`);

isRunning()

Check if the node is currently running.

isRunning(): boolean

Returns

boolean - true if the node is running, false otherwise

Example

if (huinet.isRunning()) {
  console.log('Node is active');
} else {
  console.log('Node is stopped');
}

disconnectFromNode()

Disconnect from a connected node.

async disconnectFromNode(nodeID: string): Promise<boolean>

Parameters

  • nodeID (string): The NodeID of the node to disconnect from

Returns

boolean - true if disconnection succeeded, false otherwise

Example

const success = await huinet.disconnectFromNode(targetNodeID);

if (success) {
  console.log('Disconnected successfully');
} else {
  console.log('Node not connected or disconnection failed');
}

Routing Management

getConnectedNodes()

Get a list of all connected node IDs.

getConnectedNodes(): string[]

Returns

string[] - Array of connected NodeIDs

Example

const connected = huinet.getConnectedNodes();
console.log(`Connected nodes: ${connected.length}`);

for (const nodeID of connected) {
  console.log(`- ${nodeID}`);
}

getRoutingStats()

Get statistics about the routing table.

getRoutingStats(): RoutingStats

Returns

RoutingStats - Object containing routing statistics:

  • totalNodes (number): Total number of nodes
  • coreCount (number): Number of core connections
  • activeCount (number): Number of active connections
  • knownCount (number): Number of known nodes
  • connectionCounts (Record<string, number>): Connection count per node

Example

const stats = huinet.getRoutingStats();
console.log(`Total nodes: ${stats.totalNodes}`);
console.log(`Core: ${stats.coreCount}, Active: ${stats.activeCount}, Known: ${stats.knownCount}`);

promoteToActive()

Manually promote a node to the Active layer.

promoteToActive(nodeID: string): boolean

Parameters

  • nodeID (string): The NodeID of the node to promote

Returns

boolean - true if promotion succeeded, false otherwise

Example

const promoted = huinet.promoteToActive(nodeID);

if (promoted) {
  console.log('Node promoted to Active layer');
} else {
  console.log('Promotion failed - node not found');
}

promoteToCore()

Manually promote a node to the Core layer.

promoteToCore(nodeID: string): boolean

Parameters

  • nodeID (string): The NodeID of the node to promote

Returns

boolean - true if promotion succeeded, false otherwise

Example

const promoted = huinet.promoteToCore(nodeID);

if (promoted) {
  console.log('Node promoted to Core layer - will maintain persistent connection');
}

demoteFromActive()

Demote a node from Active to Known layer.

demoteFromActive(nodeID: string): boolean

Parameters

  • nodeID (string): The NodeID of the node to demote

Returns

boolean - true if demotion succeeded, false otherwise

Example

const demoted = huinet.demoteFromActive(nodeID);

if (demoted) {
  console.log('Node demoted from Active to Known');
}

demoteFromCore()

Demote a node from Core to Active layer.

demoteFromCore(nodeID: string): boolean

Parameters

  • nodeID (string): The NodeID of the node to demote

Returns

boolean - true if demotion succeeded, false otherwise

Example

const demoted = huinet.demoteFromCore(nodeID);

if (demoted) {
  console.log('Node demoted from Core to Active');
}

Network Utilities

getLocalIPs()

Get all local IP addresses with optional filtering.

getLocalIPs(options?: GetLocalIPOptions): string[]

Parameters

  • options (GetLocalIPOptions, optional):
    • ipv4Only (boolean): Return only IPv4 addresses
    • excludeInternal (boolean): Exclude loopback addresses
    • interfaceName (string): Filter by interface name

Returns

string[] - Array of IP addresses

Example

// Get all local IPs
const allIPs = huinet.getLocalIPs();

// Get only IPv4 addresses
const ipv4Only = huinet.getLocalIPs({ ipv4Only: true });

// Exclude loopback (127.0.0.1)
const externalIPs = huinet.getLocalIPs({ excludeInternal: true });

getPrimaryLocalIP()

Get the primary local IP address (non-loopback IPv4).

getPrimaryLocalIP(): string

Returns

string - The primary local IP address

Example

const primaryIP = huinet.getPrimaryLocalIP();
console.log(`Primary IP: ${primaryIP}`);

isSameNetwork()

Check if a node is on the same local network.

isSameNetwork(nodeID: string, subnetMask?: number): boolean

Parameters

  • nodeID (string): The NodeID of the target node
  • subnetMask (number, optional): Subnet mask bits (default: 24)

Returns

boolean - true if on the same network, false otherwise

Example

// Check if node is on same /24 subnet
const sameNetwork = huinet.isSameNetwork(targetNodeID, 24);

if (sameNetwork) {
  console.log('Node is on the same local network');
} else {
  console.log('Node is on a different network');
}

// Check with custom subnet mask
const sameSubnet = huinet.isSameNetwork(targetNodeID, 16); // /16 subnet

Events

HuiNet extends EventEmitter and emits the following events:

ready

Emitted when the node has started and is ready to accept connections.

huinet.on('ready', () => {
  console.log('Node is ready');
});

Callback Signature: () => void


message

Emitted when a message is received from a peer node.

huinet.on('message', (from: NodeID, data: any) => {
  console.log(`Received from ${from}:`, data);
});

Callback Signature: (from: NodeID, data: any) => void

Parameters:

  • from (NodeID): The NodeID of the sender
  • data (any): The message data (parsed JSON object)

Example

huinet.on('message', (from, data) => {
  if (data.type === 'chat') {
    console.log(`${from}: ${data.text}`);
  } else if (data.type === 'file-transfer') {
    handleFileTransfer(from, data);
  }
});

peerConnected

Emitted when a connection to a peer node is established.

huinet.on('peerConnected', (nodeID: NodeID, type?: ConnectionType) => {
  console.log(`Connected to ${nodeID}`);
});

Callback Signature: (nodeID: NodeID, type?: ConnectionType) => void

Parameters:

  • nodeID (NodeID): The NodeID of the connected peer
  • type (ConnectionType, optional): The connection type (CORE, ACTIVE, or ON_DEMAND)

Example

huinet.on('peerConnected', (nodeID, type) => {
  console.log(`New connection: ${nodeID} (${type || 'unknown'})`);
});

peerDisconnected

Emitted when a peer node disconnects.

huinet.on('peerDisconnected', (nodeID: NodeID) => {
  console.log(`Disconnected from ${nodeID}`);
});

Callback Signature: (nodeID: NodeID) => void

Parameters:

  • nodeID (NodeID): The NodeID of the disconnected peer

Example

huinet.on('peerDisconnected', (nodeID) => {
  console.log(`Peer ${nodeID} disconnected`);

  // Attempt to reconnect after delay
  setTimeout(async () => {
    const node = huinet.getRoutingTable().getKnownNode(nodeID);
    if (node && node.addresses.length > 0) {
      const addr = node.addresses[0];
      await huinet.connectToNode(addr.host, addr.port, nodeID);
    }
  }, 5000);
});

nodeDiscovered

Emitted when a new node is discovered through mDNS.

huinet.on('nodeDiscovered', (node: DiscoveredNode) => {
  console.log(`Discovered ${node.nodeId}`);
});

Callback Signature: (node: DiscoveredNode) => void

Parameters:

  • node (DiscoveredNode): Information about the discovered node

Example

huinet.on('nodeDiscovered', (node) => {
  console.log(`Discovered node: ${node.nodeId} at ${node.address}`);
});

error

Emitted when an error occurs.

huinet.on('error', (error: Error) => {
  console.error('Error:', error);
});

Callback Signature: (error: Error) => void

Parameters:

  • error (Error): The error object

Example

huinet.on('error', (error) => {
  console.error('HuiNet error:', error.message);

  // Handle specific errors
  if (error.message.includes('Unknown node')) {
    console.log('Node not found in routing table');
  }
});

Type Definitions

NodeID

A NodeID is a string representing a unique node identifier.

type NodeID = string;

Format: Base58-encoded SHA-256 hash of a public key (43-44 characters)

Example: 'QmXxx...'


MessageData

Interface for message data structure.

interface MessageData {
  from: NodeID;           // Sender's NodeID
  to: NodeID;             // Recipient's NodeID
  timestamp: number;       // Unix timestamp in milliseconds
  data: any;              // Actual message payload
}

Example:

const message: MessageData = {
  from: 'QmSender123...',
  to: 'QmRecipient456...',
  timestamp: Date.now(),
  data: {
    type: 'chat',
    text: 'Hello, World!'
  }
};

NodeState

Enum representing the state of a node in the routing table.

enum NodeState {
  UNKNOWN = 'UNKNOWN',      // Node state not yet determined
  ONLINE = 'ONLINE',        // Node is online and reachable
  OFFLINE = 'OFFLINE',      // Node is offline or unreachable
  RESTRICTED = 'RESTRICTED' // Node is restricted/blocked
}

Values:

  • UNKNOWN: Initial state when a node is discovered but not yet verified
  • ONLINE: Node has been successfully contacted
  • OFFLINE: Node is known to be offline
  • RESTRICTED: Node is blocked or restricted

ConnectionType

Enum representing the type of connection.

enum ConnectionType {
  CORE = 'CORE',           // Persistent connection to super nodes
  ACTIVE = 'ACTIVE',       // Cached connection to recently used nodes
  ON_DEMAND = 'ON_DEMAND'  // Temporary connection for one-off operations
}

ConnectionState

Enum representing the state of a connection.

enum ConnectionState {
  CONNECTING = 'CONNECTING',     // Connection is being established
  CONNECTED = 'CONNECTED',       // Connection is active
  IDLE = 'IDLE',                 // Connection is idle
  DISCONNECTED = 'DISCONNECTED', // Connection is closed
  RECONNECTING = 'RECONNECTING', // Reconnection in progress
  FAILED = 'FAILED'              // Connection failed
}

TransportType

Enum representing the transport protocol.

enum TransportType {
  TCP = 'tcp',         // TCP transport
  WS = 'ws',           // WebSocket transport
  QUIC = 'quic',       // QUIC transport
  RELAY = 'relay'      // Relay transport
}

Utility Functions

generateKeyPair()

Generate a new cryptographic key pair for node identity.

function generateKeyPair(): KeyPair

Returns

KeyPair - Object containing publicKey and secretKey buffers

Example

import { generateKeyPair } from '@huinet/network';

const keyPair = generateKeyPair();
console.log('Public Key:', keyPair.publicKey.toString('hex'));
console.log('Secret Key:', keyPair.secretKey.toString('hex'));

deriveNodeID()

Derive a NodeID from a public key.

function deriveNodeID(publicKey: Buffer): NodeID

Parameters

  • publicKey (Buffer): The public key buffer (32 bytes)

Returns

NodeID - The derived NodeID (Base58-encoded string)

Example

import { deriveNodeID } from '@huinet/network';

const nodeID = deriveNodeID(publicKey);
console.log('NodeID:', nodeID);

validateNodeID()

Validate a NodeID string format.

function validateNodeID(nodeID: string): boolean

Parameters

  • nodeID (string): The NodeID to validate

Returns

boolean - true if valid, false otherwise

Example

import { validateNodeID } from '@huinet/network';

const isValid = validateNodeID('QmXxx...');
if (isValid) {
  console.log('Valid NodeID');
} else {
  console.log('Invalid NodeID');
}

Complete Usage Example

import { HuiNet, HuiNetConfig, generateKeyPair } from '@huinet/network';

// Create configuration
const config: HuiNetConfig = {
  listenPort: 8000,
  listenHost: '0.0.0.0',
  bootstrapNodes: ['192.168.1.100:8000'],
  maxCoreConnections: 10,
  maxActiveConnections: 50,
  enableMDNS: true
};

// Initialize HuiNet
const huinet = new HuiNet(config);

// Set up event handlers
huinet.on('ready', () => {
  console.log(`Node ready! ID: ${huinet.getNodeID()}`);
});

huinet.on('message', (from, data) => {
  console.log(`Message from ${from}:`, data);
});

huinet.on('peerConnected', (nodeID) => {
  console.log(`Connected to ${nodeID}`);
});

huinet.on('peerDisconnected', (nodeID) => {
  console.log(`Disconnected from ${nodeID}`);
});

huinet.on('nodeDiscovered', (node) => {
  console.log(`Discovered ${node.nodeId}`);
});

huinet.on('error', (error) => {
  console.error('Error:', error);
});

// Start the node
await huinet.start();

// Send a message
await huinet.send(targetNodeID, {
  type: 'chat',
  text: 'Hello from HuiNet!'
});

// Get routing information
const routingTable = huinet.getRoutingTable();
const allNodes = routingTable.getAllKnownNodes();
console.log(`Known nodes: ${allNodes.length}`);

// Graceful shutdown
process.on('SIGINT', async () => {
  await huinet.stop();
  process.exit(0);
});

Additional Resources