155 lines
4.5 KiB
TypeScript
155 lines
4.5 KiB
TypeScript
/**
|
|
* 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<string, string | string[]>;
|
|
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
|
|
};
|
|
}
|