Files
suaveplan/docs/old-network-planning/PHASE_3_IMPLEMENTATION_PLAN.md
2026-05-27 23:29:53 +01:00

14 KiB

Network Library Phase 3: Message Routing Implementation Plan

Having successfully completed Phase 2 with the Transport Layer implementation, we're now ready to move on to Phase 3, which focuses on Message Routing. This phase will build upon our transport capabilities to implement intelligent routing of messages across the network.

Overview

Phase 3 focuses on creating a robust message routing system that can efficiently deliver messages between nodes, even when there's no direct connection between sender and recipient. This includes message prioritization, route discovery, and quality-of-service features.

Implementation Goals

  1. Message Router Framework: Create the core routing infrastructure
  2. Routing Algorithms: Implement multiple routing strategies
  3. Prioritization System: Build a quality-of-service framework
  4. Message Batching: Optimize network usage with message grouping
  5. Route Discovery: Implement mechanisms to find optimal paths
  6. Plugin Extension Points: Allow customization of routing behaviors

Detailed Implementation Plan

1. Message Router Core

First, we'll define the interfaces and base classes for the routing system:

// src/router/types.ts
export interface RouteInfo {
  nextHopId: string;
  pathLength: number;
  estimatedLatency: number;
  reliability: number;
  lastUpdated: number;
}

export interface RoutingTable {
  getRoute(targetId: string): RouteInfo | null;
  addRoute(targetId: string, route: RouteInfo): void;
  removeRoute(targetId: string): boolean;
  getAllRoutes(): Map<string, RouteInfo>;
  clear(): void;
}

export interface IMessageRouter {
  routeMessage(message: NetworkMessage): Promise<void>;
  addRoutingTable(table: RoutingTable): void;
  findRoute(targetId: string): RouteInfo | null;
  updateRoutes(): Promise<void>;
}

export enum RoutingStrategy {
  DIRECT = 'direct',
  FLOOD = 'flood',
  SHORTEST_PATH = 'shortest-path',
  RANDOM = 'random',
  CUSTOM = 'custom'
}

export interface RoutingConfig {
  strategy: RoutingStrategy;
  prioritization: boolean;
  batchingEnabled: boolean;
  batchInterval: number;
  maxBatchSize: number;
  retryCount: number;
  routeUpdateInterval: number;
}

2. Basic Routing Table Implementation

Next, we'll implement a basic routing table:

// src/router/routing-table.ts
export class BasicRoutingTable implements RoutingTable {
  private _routes: Map<string, RouteInfo> = new Map();
  
  getRoute(targetId: string): RouteInfo | null {
    return this._routes.get(targetId) || null;
  }
  
  addRoute(targetId: string, route: RouteInfo): void {
    this._routes.set(targetId, route);
  }
  
  removeRoute(targetId: string): boolean {
    return this._routes.delete(targetId);
  }
  
  getAllRoutes(): Map<string, RouteInfo> {
    return new Map(this._routes);
  }
  
  clear(): void {
    this._routes.clear();
  }
  
  // Additional utility methods for route optimization
  getBestRoute(targetId: string, criteria: 'latency' | 'reliability' | 'pathLength'): RouteInfo | null {
    // Implementation
  }
  
  pruneStaleRoutes(maxAge: number): number {
    // Implementation
  }
}

3. Base Message Router

Now we'll implement the base message router class:

// src/router/base-message-router.ts
export abstract class BaseMessageRouter implements IMessageRouter {
  protected _routingTables: RoutingTable[] = [];
  protected _node: NetworkNode;
  protected _config: RoutingConfig;
  protected _messageQueue: PriorityQueue<NetworkMessage>;
  protected _batchingEnabled: boolean;
  
  constructor(node: NetworkNode, config?: Partial<RoutingConfig>) {
    this._node = node;
    this._config = { ...this._getDefaultConfig(), ...config };
    this._batchingEnabled = this._config.batchingEnabled;
    this._messageQueue = new PriorityQueue<NetworkMessage>((a, b) => 
      (a.priority || MessagePriority.NORMAL) - (b.priority || MessagePriority.NORMAL)
    );
    
    // Set up processing interval if batching is enabled
    if (this._batchingEnabled) {
      this._setupBatchProcessing();
    }
  }
  
  abstract routeMessage(message: NetworkMessage): Promise<void>;
  
  addRoutingTable(table: RoutingTable): void {
    this._routingTables.push(table);
  }
  
  findRoute(targetId: string): RouteInfo | null {
    // Check each routing table for a route
    for (const table of this._routingTables) {
      const route = table.getRoute(targetId);
      if (route) {
        return route;
      }
    }
    
    return null;
  }
  
  abstract updateRoutes(): Promise<void>;
  
  protected _getDefaultConfig(): RoutingConfig {
    return {
      strategy: RoutingStrategy.DIRECT,
      prioritization: true,
      batchingEnabled: false,
      batchInterval: 100,
      maxBatchSize: 10,
      retryCount: 3,
      routeUpdateInterval: 30000 // 30 seconds
    };
  }
  
  protected _setupBatchProcessing(): void {
    // Set up interval to process message batches
  }
  
  protected async _processBatch(): Promise<void> {
    // Process a batch of messages based on priority
  }
}

4. Routing Strategy Implementations

We'll implement multiple routing strategies:

// src/router/strategies/direct-router.ts
export class DirectMessageRouter extends BaseMessageRouter {
  async routeMessage(message: NetworkMessage): Promise<void> {
    // Direct delivery to target if connected
    if (this._node.transport && message.targetId) {
      await this._node.transport.sendTo(message.targetId, message);
    } else {
      throw new Error('Cannot route message: no transport or target ID');
    }
  }
  
  async updateRoutes(): Promise<void> {
    // Direct routing doesn't need route updates
    return Promise.resolve();
  }
}

// src/router/strategies/flood-router.ts
export class FloodMessageRouter extends BaseMessageRouter {
  async routeMessage(message: NetworkMessage): Promise<void> {
    // Send to all connected nodes except source
    const sentTo = new Set<string>();
    
    // Send to parent if exists
    if (this._node.parent && this._node.parent.id !== message.senderId) {
      await this._node.parent.sendMessage(message);
      sentTo.add(this._node.parent.id);
    }
    
    // Send to all children
    for (const child of this._node.children) {
      if (child.id !== message.senderId && !sentTo.has(child.id)) {
        await child.sendMessage(message);
        sentTo.add(child.id);
      }
    }
    
    // Send to siblings
    for (const sibling of this._node.siblings) {
      if (sibling.id !== message.senderId && !sentTo.has(sibling.id)) {
        await sibling.sendMessage(message);
        sentTo.add(sibling.id);
      }
    }
  }
  
  async updateRoutes(): Promise<void> {
    // Flooding doesn't need route updates
    return Promise.resolve();
  }
}

5. Message Prioritization System

Next, we'll implement message prioritization for quality-of-service:

// src/router/priority-queue.ts
export class PriorityQueue<T> {
  private _items: T[] = [];
  private _comparator: (a: T, b: T) => number;
  
  constructor(comparator: (a: T, b: T) => number) {
    this._comparator = comparator;
  }
  
  enqueue(item: T): void {
    this._items.push(item);
    this._items.sort(this._comparator);
  }
  
  dequeue(): T | undefined {
    return this._items.shift();
  }
  
  peek(): T | undefined {
    return this._items[0];
  }
  
  get size(): number {
    return this._items.length;
  }
  
  isEmpty(): boolean {
    return this._items.length === 0;
  }
  
  clear(): void {
    this._items = [];
  }
}

// src/router/message-batching.ts
export class MessageBatch {
  messages: NetworkMessage[] = [];
  priority: MessagePriority;
  timestamp: number;
  
  constructor(priority: MessagePriority = MessagePriority.NORMAL) {
    this.priority = priority;
    this.timestamp = Date.now();
  }
  
  addMessage(message: NetworkMessage): void {
    this.messages.push(message);
  }
  
  get size(): number {
    return this.messages.length;
  }
  
  get averagePriority(): number {
    if (this.messages.length === 0) return this.priority;
    
    const sum = this.messages.reduce((acc, msg) => 
      acc + (msg.priority || MessagePriority.NORMAL), 0);
    return sum / this.messages.length;
  }
}

6. Route Discovery System

We'll implement route discovery and optimization:

// src/router/route-discovery.ts
export class RouteDiscoveryManager {
  private _node: NetworkNode;
  private _routingTable: RoutingTable;
  private _discoveryInProgress: boolean = false;
  
  constructor(node: NetworkNode, routingTable: RoutingTable) {
    this._node = node;
    this._routingTable = routingTable;
  }
  
  async discoverRoutes(): Promise<void> {
    if (this._discoveryInProgress) return;
    
    this._discoveryInProgress = true;
    
    try {
      // Send discovery messages to immediate connections
      await this._sendDiscoveryRequests();
      
      // Wait for responses
      await this._collectResponses();
      
      // Update routing table
      this._updateRoutingTable();
    } finally {
      this._discoveryInProgress = false;
    }
  }
  
  private async _sendDiscoveryRequests(): Promise<void> {
    // Implementation
  }
  
  private async _collectResponses(): Promise<void> {
    // Implementation
  }
  
  private _updateRoutingTable(): void {
    // Implementation
  }
}

7. Advanced Router with Plugin Support

Finally, we'll create an advanced router that supports plugins:

// src/router/advanced-message-router.ts
export interface RouterPlugin {
  id: string;
  onMessageRouting(message: NetworkMessage, nextHop: string | null): Promise<string | null>;
  onRoutingError(error: Error, message: NetworkMessage): Promise<boolean>;
  onRouteDiscovery(routes: Map<string, RouteInfo>): Promise<void>;
}

export class AdvancedMessageRouter extends BaseMessageRouter {
  private _plugins: RouterPlugin[] = [];
  private _discoveryManager: RouteDiscoveryManager;
  
  constructor(node: NetworkNode, config?: Partial<RoutingConfig>) {
    super(node, config);
    
    const routingTable = new BasicRoutingTable();
    this._routingTables.push(routingTable);
    this._discoveryManager = new RouteDiscoveryManager(node, routingTable);
    
    // Set up periodic route updates
    if (this._config.routeUpdateInterval > 0) {
      setInterval(() => this.updateRoutes(), this._config.routeUpdateInterval);
    }
  }
  
  async routeMessage(message: NetworkMessage): Promise<void> {
    // If batching is enabled, queue the message
    if (this._batchingEnabled) {
      this._messageQueue.enqueue(message);
      return;
    }
    
    // Otherwise, route immediately
    await this._routeSingleMessage(message);
  }
  
  async updateRoutes(): Promise<void> {
    await this._discoveryManager.discoverRoutes();
  }
  
  registerPlugin(plugin: RouterPlugin): void {
    this._plugins.push(plugin);
  }
  
  unregisterPlugin(pluginId: string): boolean {
    const index = this._plugins.findIndex(p => p.id === pluginId);
    if (index >= 0) {
      this._plugins.splice(index, 1);
      return true;
    }
    return false;
  }
  
  private async _routeSingleMessage(message: NetworkMessage): Promise<void> {
    // Find the route
    let nextHop = this._findNextHop(message);
    
    // Allow plugins to modify the route
    for (const plugin of this._plugins) {
      nextHop = await plugin.onMessageRouting(message, nextHop) || nextHop;
    }
    
    // If we have a next hop, send the message
    if (nextHop && this._node.transport) {
      try {
        await this._node.transport.sendTo(nextHop, message);
      } catch (error) {
        // Let plugins handle the error
        let handled = false;
        for (const plugin of this._plugins) {
          handled = await plugin.onRoutingError(error as Error, message) || handled;
        }
        
        // If not handled by plugins, rethrow
        if (!handled) {
          throw error;
        }
      }
    } else {
      throw new Error('No route found for message');
    }
  }
  
  private _findNextHop(message: NetworkMessage): string | null {
    if (!message.targetId) {
      return null;
    }
    
    // Direct delivery if we're connected to the target
    if (this._node.transport && this._node.transport.state === TransportState.CONNECTED) {
      // Check if target is a direct connection
      return message.targetId;
    }
    
    // Otherwise, look up in routing table
    const route = this.findRoute(message.targetId);
    if (route) {
      return route.nextHopId;
    }
    
    return null;
  }
}

Testing Plan

  1. Unit Tests:

    • Test routing table operations
    • Test message prioritization
    • Test different routing strategies
    • Test plugin integration
  2. Integration Tests:

    • Test end-to-end message routing
    • Test route discovery
    • Test fallback behaviors
    • Test with different network topologies
  3. Performance Tests:

    • Test routing with high message volumes
    • Test batching performance
    • Test priority queuing under load

Implementation Schedule

  1. Week 1: Implement routing interfaces and basic routing table
  2. Week 2: Implement base router and direct routing strategy
  3. Week 3: Implement flooding and shortest-path strategies
  4. Week 4: Implement prioritization and batching
  5. Week 5: Implement route discovery
  6. Week 6: Implement advanced router with plugin support

Conclusion

This plan outlines the implementation of Phase 3, focusing on the Message Routing Layer. This builds upon the Transport Layer completed in Phase 2 and will provide the foundation for more advanced network capabilities in future phases. The modular design with plugin support ensures we can extend functionality as needed.