update
This commit is contained in:
@ -93,6 +93,12 @@ export class SmartCertManager {
|
||||
*/
|
||||
public setUpdateRoutesCallback(callback: (routes: IRouteConfig[]) => Promise<void>): void {
|
||||
this.updateRoutesCallback = callback;
|
||||
try {
|
||||
logger.log('debug', 'Route update callback set successfully', { component: 'certificate-manager' });
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log('[DEBUG] Route update callback set successfully');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -399,13 +405,23 @@ export class SmartCertManager {
|
||||
private async addChallengeRoute(): Promise<void> {
|
||||
// Check with state manager first
|
||||
if (this.acmeStateManager && this.acmeStateManager.isChallengeRouteActive()) {
|
||||
logger.log('info', 'Challenge route already active in global state, skipping', { component: 'certificate-manager' });
|
||||
try {
|
||||
logger.log('info', 'Challenge route already active in global state, skipping', { component: 'certificate-manager' });
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log('[INFO] Challenge route already active in global state, skipping');
|
||||
}
|
||||
this.challengeRouteActive = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.challengeRouteActive) {
|
||||
logger.log('info', 'Challenge route already active locally, skipping', { component: 'certificate-manager' });
|
||||
try {
|
||||
logger.log('info', 'Challenge route already active locally, skipping', { component: 'certificate-manager' });
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log('[INFO] Challenge route already active locally, skipping');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -445,7 +461,24 @@ export class SmartCertManager {
|
||||
// Add the challenge route
|
||||
const challengeRoute = this.challengeRoute;
|
||||
|
||||
// If the port is already in use by other routes in this SmartProxy instance,
|
||||
// we can safely add the ACME challenge route without trying to bind to the port again
|
||||
try {
|
||||
// Check if we're already listening on the challenge port
|
||||
const isPortAlreadyBound = portInUseByRoutes;
|
||||
|
||||
if (isPortAlreadyBound) {
|
||||
try {
|
||||
logger.log('info', `Port ${challengePort} is already bound by SmartProxy, adding ACME challenge route without rebinding`, {
|
||||
port: challengePort,
|
||||
component: 'certificate-manager'
|
||||
});
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[INFO] Port ${challengePort} is already bound by SmartProxy, adding ACME challenge route without rebinding`);
|
||||
}
|
||||
}
|
||||
|
||||
const updatedRoutes = [...this.routes, challengeRoute];
|
||||
await this.updateRoutesCallback(updatedRoutes);
|
||||
this.challengeRouteActive = true;
|
||||
@ -455,15 +488,25 @@ export class SmartCertManager {
|
||||
this.acmeStateManager.addChallengeRoute(challengeRoute);
|
||||
}
|
||||
|
||||
logger.log('info', 'ACME challenge route successfully added', { component: 'certificate-manager' });
|
||||
try {
|
||||
logger.log('info', 'ACME challenge route successfully added', { component: 'certificate-manager' });
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log('[INFO] ACME challenge route successfully added');
|
||||
}
|
||||
} catch (error) {
|
||||
// Handle specific EADDRINUSE errors differently based on whether it's an internal conflict
|
||||
if ((error as any).code === 'EADDRINUSE') {
|
||||
logger.log('error', `Failed to add challenge route on port ${challengePort}: ${error.message}`, {
|
||||
error: error.message,
|
||||
port: challengePort,
|
||||
component: 'certificate-manager'
|
||||
});
|
||||
try {
|
||||
logger.log('error', `Failed to add challenge route on port ${challengePort}: ${error.message}`, {
|
||||
error: (error as Error).message,
|
||||
port: challengePort,
|
||||
component: 'certificate-manager'
|
||||
});
|
||||
} catch (logError) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[ERROR] Failed to add challenge route on port ${challengePort}: ${error.message}`);
|
||||
}
|
||||
|
||||
// Provide a more informative error message
|
||||
throw new Error(
|
||||
@ -474,10 +517,15 @@ export class SmartCertManager {
|
||||
}
|
||||
|
||||
// Log and rethrow other errors
|
||||
logger.log('error', `Failed to add challenge route: ${error.message}`, {
|
||||
error: error.message,
|
||||
component: 'certificate-manager'
|
||||
});
|
||||
try {
|
||||
logger.log('error', `Failed to add challenge route: ${(error as Error).message}`, {
|
||||
error: (error as Error).message,
|
||||
component: 'certificate-manager'
|
||||
});
|
||||
} catch (logError) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[ERROR] Failed to add challenge route: ${(error as Error).message}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -487,7 +535,12 @@ export class SmartCertManager {
|
||||
*/
|
||||
private async removeChallengeRoute(): Promise<void> {
|
||||
if (!this.challengeRouteActive) {
|
||||
logger.log('info', 'Challenge route not active, skipping removal', { component: 'certificate-manager' });
|
||||
try {
|
||||
logger.log('info', 'Challenge route not active, skipping removal', { component: 'certificate-manager' });
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log('[INFO] Challenge route not active, skipping removal');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -505,9 +558,19 @@ export class SmartCertManager {
|
||||
this.acmeStateManager.removeChallengeRoute('acme-challenge');
|
||||
}
|
||||
|
||||
logger.log('info', 'ACME challenge route successfully removed', { component: 'certificate-manager' });
|
||||
try {
|
||||
logger.log('info', 'ACME challenge route successfully removed', { component: 'certificate-manager' });
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log('[INFO] ACME challenge route successfully removed');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to remove challenge route: ${error.message}`, { error: error.message, component: 'certificate-manager' });
|
||||
try {
|
||||
logger.log('error', `Failed to remove challenge route: ${error.message}`, { error: error.message, component: 'certificate-manager' });
|
||||
} catch (logError) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[ERROR] Failed to remove challenge route: ${error.message}`);
|
||||
}
|
||||
// Reset the flag even on error to avoid getting stuck
|
||||
this.challengeRouteActive = false;
|
||||
throw error;
|
||||
|
@ -46,10 +46,14 @@ export class PortManager {
|
||||
if (this.servers.has(port)) {
|
||||
// Port is already bound, just increment the reference count
|
||||
this.incrementPortRefCount(port);
|
||||
logger.log('debug', `PortManager: Port ${port} is already bound by SmartProxy, reusing binding`, {
|
||||
port,
|
||||
component: 'port-manager'
|
||||
});
|
||||
try {
|
||||
logger.log('debug', `PortManager: Port ${port} is already bound by SmartProxy, reusing binding`, {
|
||||
port,
|
||||
component: 'port-manager'
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(`[DEBUG] PortManager: Port ${port} is already bound by SmartProxy, reusing binding`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -68,24 +72,34 @@ export class PortManager {
|
||||
// Delegate to route connection handler
|
||||
this.routeConnectionHandler.handleConnection(socket);
|
||||
}).on('error', (err: Error) => {
|
||||
logger.log('error', `Server Error on port ${port}: ${err.message}`, {
|
||||
port,
|
||||
error: err.message,
|
||||
component: 'port-manager'
|
||||
});
|
||||
try {
|
||||
logger.log('error', `Server Error on port ${port}: ${err.message}`, {
|
||||
port,
|
||||
error: err.message,
|
||||
component: 'port-manager'
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`[ERROR] Server Error on port ${port}: ${err.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Start listening on the port
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
server.listen(port, () => {
|
||||
const isHttpProxyPort = this.settings.useHttpProxy?.includes(port);
|
||||
logger.log('info', `SmartProxy -> OK: Now listening on port ${port}${
|
||||
isHttpProxyPort ? ' (HttpProxy forwarding enabled)' : ''
|
||||
}`, {
|
||||
port,
|
||||
isHttpProxyPort: !!isHttpProxyPort,
|
||||
component: 'port-manager'
|
||||
});
|
||||
try {
|
||||
logger.log('info', `SmartProxy -> OK: Now listening on port ${port}${
|
||||
isHttpProxyPort ? ' (HttpProxy forwarding enabled)' : ''
|
||||
}`, {
|
||||
port,
|
||||
isHttpProxyPort: !!isHttpProxyPort,
|
||||
component: 'port-manager'
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(`[INFO] SmartProxy -> OK: Now listening on port ${port}${
|
||||
isHttpProxyPort ? ' (HttpProxy forwarding enabled)' : ''
|
||||
}`);
|
||||
}
|
||||
|
||||
// Store the server reference
|
||||
this.servers.set(port, server);
|
||||
|
@ -521,7 +521,12 @@ export class SmartProxy extends plugins.EventEmitter {
|
||||
const challengeRouteExists = this.settings.routes.some(r => r.name === 'acme-challenge');
|
||||
|
||||
if (!challengeRouteExists) {
|
||||
logger.log('info', 'Challenge route successfully removed from routes');
|
||||
try {
|
||||
logger.log('info', 'Challenge route successfully removed from routes');
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log('[INFO] Challenge route successfully removed from routes');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -530,7 +535,12 @@ export class SmartProxy extends plugins.EventEmitter {
|
||||
}
|
||||
|
||||
const error = `Failed to verify challenge route removal after ${maxRetries} attempts`;
|
||||
logger.log('error', error);
|
||||
try {
|
||||
logger.log('error', error);
|
||||
} catch (logError) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[ERROR] ${error}`);
|
||||
}
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
@ -559,7 +569,12 @@ export class SmartProxy extends plugins.EventEmitter {
|
||||
*/
|
||||
public async updateRoutes(newRoutes: IRouteConfig[]): Promise<void> {
|
||||
return this.routeUpdateLock.runExclusive(async () => {
|
||||
logger.log('info', `Updating routes (${newRoutes.length} routes)`, { routeCount: newRoutes.length, component: 'route-manager' });
|
||||
try {
|
||||
logger.log('info', `Updating routes (${newRoutes.length} routes)`, { routeCount: newRoutes.length, component: 'route-manager' });
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[INFO] Updating routes (${newRoutes.length} routes)`);
|
||||
}
|
||||
|
||||
// Track port usage before and after updates
|
||||
const oldPortUsage = this.updatePortUsageMap(this.settings.routes);
|
||||
@ -611,19 +626,29 @@ export class SmartProxy extends plugins.EventEmitter {
|
||||
|
||||
// Release orphaned ports first
|
||||
if (orphanedPorts.length > 0) {
|
||||
logger.log('info', `Releasing ${orphanedPorts.length} orphaned ports: ${orphanedPorts.join(', ')}`, {
|
||||
ports: orphanedPorts,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
try {
|
||||
logger.log('info', `Releasing ${orphanedPorts.length} orphaned ports: ${orphanedPorts.join(', ')}`, {
|
||||
ports: orphanedPorts,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[INFO] Releasing ${orphanedPorts.length} orphaned ports: ${orphanedPorts.join(', ')}`);
|
||||
}
|
||||
await this.portManager.removePorts(orphanedPorts);
|
||||
}
|
||||
|
||||
// Add new ports
|
||||
if (newBindingPorts.length > 0) {
|
||||
logger.log('info', `Binding to ${newBindingPorts.length} new ports: ${newBindingPorts.join(', ')}`, {
|
||||
ports: newBindingPorts,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
try {
|
||||
logger.log('info', `Binding to ${newBindingPorts.length} new ports: ${newBindingPorts.join(', ')}`, {
|
||||
ports: newBindingPorts,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[INFO] Binding to ${newBindingPorts.length} new ports: ${newBindingPorts.join(', ')}`);
|
||||
}
|
||||
await this.portManager.addPorts(newBindingPorts);
|
||||
}
|
||||
|
||||
@ -646,6 +671,22 @@ export class SmartProxy extends plugins.EventEmitter {
|
||||
// Store global state before stopping
|
||||
this.globalChallengeRouteActive = existingState.challengeRouteActive;
|
||||
|
||||
// Only stop the cert manager if absolutely necessary
|
||||
// First check if there's an ACME route on the same port already
|
||||
const acmePort = existingAcmeOptions?.port || 80;
|
||||
const acmePortInUse = newPortUsage.has(acmePort) && newPortUsage.get(acmePort)!.size > 0;
|
||||
|
||||
try {
|
||||
logger.log('debug', `ACME port ${acmePort} ${acmePortInUse ? 'is' : 'is not'} already in use by other routes`, {
|
||||
port: acmePort,
|
||||
inUse: acmePortInUse,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[DEBUG] ACME port ${acmePort} ${acmePortInUse ? 'is' : 'is not'} already in use by other routes`);
|
||||
}
|
||||
|
||||
await this.certManager.stop();
|
||||
|
||||
// Verify the challenge route has been properly removed
|
||||
@ -721,11 +762,16 @@ export class SmartProxy extends plugins.EventEmitter {
|
||||
|
||||
// Log port usage for debugging
|
||||
for (const [port, routes] of portUsage.entries()) {
|
||||
logger.log('debug', `Port ${port} is used by ${routes.size} routes: ${Array.from(routes).join(', ')}`, {
|
||||
port,
|
||||
routeCount: routes.size,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
try {
|
||||
logger.log('debug', `Port ${port} is used by ${routes.size} routes: ${Array.from(routes).join(', ')}`, {
|
||||
port,
|
||||
routeCount: routes.size,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[DEBUG] Port ${port} is used by ${routes.size} routes: ${Array.from(routes).join(', ')}`);
|
||||
}
|
||||
}
|
||||
|
||||
return portUsage;
|
||||
@ -740,10 +786,15 @@ export class SmartProxy extends plugins.EventEmitter {
|
||||
for (const [port, routes] of oldUsage.entries()) {
|
||||
if (!newUsage.has(port) || newUsage.get(port)!.size === 0) {
|
||||
orphanedPorts.push(port);
|
||||
logger.log('info', `Port ${port} no longer has any associated routes, will be released`, {
|
||||
port,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
try {
|
||||
logger.log('info', `Port ${port} no longer has any associated routes, will be released`, {
|
||||
port,
|
||||
component: 'smart-proxy'
|
||||
});
|
||||
} catch (error) {
|
||||
// Silently handle logging errors
|
||||
console.log(`[INFO] Port ${port} no longer has any associated routes, will be released`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user