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