/** * Load Balancer Route Helper Functions * * This module provides utility functions for creating load balancer route configurations. */ import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget, TPortRange, IRouteContext } from '../../models/route-types.js'; /** * Create a load balancer route (round-robin between multiple backend hosts) * @param domains Domain(s) to match * @param backendsOrHosts Array of backend servers OR array of host strings (legacy) * @param portOrOptions Port number (legacy) OR options object * @param options Additional route options (legacy) * @returns Route configuration object */ export function createLoadBalancerRoute( domains: string | string[], backendsOrHosts: Array<{ host: string; port: number }> | string[], portOrOptions?: number | { tls?: { mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt'; certificate?: 'auto' | { key: string; cert: string }; }; useTls?: boolean; certificate?: 'auto' | { key: string; cert: string }; algorithm?: 'round-robin' | 'least-connections' | 'ip-hash'; healthCheck?: { path: string; interval: number; timeout: number; unhealthyThreshold: number; healthyThreshold: number; }; [key: string]: any; }, options?: { tls?: { mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt'; certificate?: 'auto' | { key: string; cert: string }; }; [key: string]: any; } ): IRouteConfig { // Handle legacy signature: (domains, hosts[], port, options) let backends: Array<{ host: string; port: number }>; let finalOptions: any; if (Array.isArray(backendsOrHosts) && backendsOrHosts.length > 0 && typeof backendsOrHosts[0] === 'string') { // Legacy signature const hosts = backendsOrHosts as string[]; const port = portOrOptions as number; backends = hosts.map(host => ({ host, port })); finalOptions = options || {}; } else { // New signature backends = backendsOrHosts as Array<{ host: string; port: number }>; finalOptions = (portOrOptions as any) || {}; } // Extract hosts and ensure all backends use the same port const port = backends[0].port; const hosts = backends.map(backend => backend.host); // Create route match const match: IRouteMatch = { ports: finalOptions.match?.ports || (finalOptions.tls || finalOptions.useTls ? 443 : 80), domains }; // Create route target const target: IRouteTarget = { host: hosts, port }; // Create route action const action: IRouteAction = { type: 'forward', targets: [target] }; // Add TLS configuration if provided if (finalOptions.tls || finalOptions.useTls) { action.tls = { mode: finalOptions.tls?.mode || 'terminate', certificate: finalOptions.tls?.certificate || finalOptions.certificate || 'auto' }; } // Add load balancing options if (finalOptions.algorithm || finalOptions.healthCheck) { action.loadBalancing = { algorithm: finalOptions.algorithm || 'round-robin', healthCheck: finalOptions.healthCheck }; } // Create the route config return { match, action, name: finalOptions.name || `Load Balancer for ${Array.isArray(domains) ? domains.join(', ') : domains}`, ...finalOptions }; } /** * Create a smart load balancer with dynamic domain-based backend selection * @param options Smart load balancer options * @returns Route configuration object */ export function createSmartLoadBalancer(options: { ports: TPortRange; domainTargets: Record; portMapper: (context: IRouteContext) => number; name?: string; defaultTarget?: string | string[]; priority?: number; [key: string]: any; }): IRouteConfig { // Extract all domain keys to create the match criteria const domains = Object.keys(options.domainTargets); // Create the smart host selector function const hostSelector = (context: IRouteContext) => { const domain = context.domain || ''; return options.domainTargets[domain] || options.defaultTarget || 'localhost'; }; // Create route match const match: IRouteMatch = { ports: options.ports, domains }; // Create route action const action: IRouteAction = { type: 'forward', targets: [{ host: hostSelector, port: options.portMapper }] }; // Create the route config return { match, action, name: options.name || `Smart Load Balancer for ${domains.join(', ')}`, priority: options.priority, ...options }; }