import type { IRouteConfig } from './models/route-types.js'; /** * Global state store for ACME operations * Tracks active challenge routes and port allocations */ export class AcmeStateManager { private activeChallengeRoutes: Map = new Map(); private acmePortAllocations: Set = new Set(); private primaryChallengeRoute: IRouteConfig | null = null; /** * Check if a challenge route is active */ public isChallengeRouteActive(): boolean { return this.activeChallengeRoutes.size > 0; } /** * Register a challenge route as active */ public addChallengeRoute(route: IRouteConfig): void { this.activeChallengeRoutes.set(route.name, route); // Track the primary challenge route if (!this.primaryChallengeRoute || route.priority > (this.primaryChallengeRoute.priority || 0)) { this.primaryChallengeRoute = route; } // Track port allocations const ports = Array.isArray(route.match.ports) ? route.match.ports : [route.match.ports]; ports.forEach(port => this.acmePortAllocations.add(port)); } /** * Remove a challenge route */ public removeChallengeRoute(routeName: string): void { const route = this.activeChallengeRoutes.get(routeName); if (!route) return; this.activeChallengeRoutes.delete(routeName); // Update primary challenge route if needed if (this.primaryChallengeRoute?.name === routeName) { this.primaryChallengeRoute = null; // Find new primary route with highest priority let highestPriority = -1; for (const [_, activeRoute] of this.activeChallengeRoutes) { const priority = activeRoute.priority || 0; if (priority > highestPriority) { highestPriority = priority; this.primaryChallengeRoute = activeRoute; } } } // Update port allocations - only remove if no other routes use this port const ports = Array.isArray(route.match.ports) ? route.match.ports : [route.match.ports]; ports.forEach(port => { let portStillUsed = false; for (const [_, activeRoute] of this.activeChallengeRoutes) { const activePorts = Array.isArray(activeRoute.match.ports) ? activeRoute.match.ports : [activeRoute.match.ports]; if (activePorts.includes(port)) { portStillUsed = true; break; } } if (!portStillUsed) { this.acmePortAllocations.delete(port); } }); } /** * Get all active challenge routes */ public getActiveChallengeRoutes(): IRouteConfig[] { return Array.from(this.activeChallengeRoutes.values()); } /** * Get the primary challenge route */ public getPrimaryChallengeRoute(): IRouteConfig | null { return this.primaryChallengeRoute; } /** * Check if a port is allocated for ACME */ public isPortAllocatedForAcme(port: number): boolean { return this.acmePortAllocations.has(port); } /** * Get all ACME ports */ public getAcmePorts(): number[] { return Array.from(this.acmePortAllocations); } /** * Clear all state (for shutdown or reset) */ public clear(): void { this.activeChallengeRoutes.clear(); this.acmePortAllocations.clear(); this.primaryChallengeRoute = null; } }