@push.rocks/smartproxy 15.0.2 → 16.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/certificate/index.d.ts +10 -4
  3. package/dist_ts/certificate/index.js +5 -7
  4. package/dist_ts/certificate/models/certificate-types.d.ts +35 -15
  5. package/dist_ts/certificate/providers/cert-provisioner.d.ts +41 -15
  6. package/dist_ts/certificate/providers/cert-provisioner.js +201 -41
  7. package/dist_ts/core/models/index.d.ts +2 -0
  8. package/dist_ts/core/models/index.js +3 -1
  9. package/dist_ts/core/models/route-context.d.ts +62 -0
  10. package/dist_ts/core/models/route-context.js +43 -0
  11. package/dist_ts/core/models/socket-augmentation.d.ts +12 -0
  12. package/dist_ts/core/models/socket-augmentation.js +18 -0
  13. package/dist_ts/core/utils/event-system.d.ts +200 -0
  14. package/dist_ts/core/utils/event-system.js +224 -0
  15. package/dist_ts/core/utils/index.d.ts +7 -0
  16. package/dist_ts/core/utils/index.js +8 -1
  17. package/dist_ts/core/utils/route-manager.d.ts +118 -0
  18. package/dist_ts/core/utils/route-manager.js +383 -0
  19. package/dist_ts/core/utils/route-utils.d.ts +94 -0
  20. package/dist_ts/core/utils/route-utils.js +264 -0
  21. package/dist_ts/core/utils/security-utils.d.ts +111 -0
  22. package/dist_ts/core/utils/security-utils.js +212 -0
  23. package/dist_ts/core/utils/shared-security-manager.d.ts +110 -0
  24. package/dist_ts/core/utils/shared-security-manager.js +252 -0
  25. package/dist_ts/core/utils/template-utils.d.ts +37 -0
  26. package/dist_ts/core/utils/template-utils.js +104 -0
  27. package/dist_ts/core/utils/websocket-utils.d.ts +23 -0
  28. package/dist_ts/core/utils/websocket-utils.js +86 -0
  29. package/dist_ts/forwarding/config/forwarding-types.d.ts +40 -76
  30. package/dist_ts/forwarding/config/forwarding-types.js +19 -18
  31. package/dist_ts/forwarding/config/index.d.ts +4 -2
  32. package/dist_ts/forwarding/config/index.js +5 -3
  33. package/dist_ts/forwarding/handlers/base-handler.js +3 -1
  34. package/dist_ts/forwarding/index.d.ts +5 -6
  35. package/dist_ts/forwarding/index.js +3 -3
  36. package/dist_ts/http/models/http-types.js +1 -1
  37. package/dist_ts/http/port80/acme-interfaces.d.ts +30 -0
  38. package/dist_ts/http/port80/acme-interfaces.js +46 -1
  39. package/dist_ts/http/port80/port80-handler.d.ts +17 -2
  40. package/dist_ts/http/port80/port80-handler.js +49 -11
  41. package/dist_ts/http/router/index.d.ts +5 -1
  42. package/dist_ts/http/router/index.js +4 -2
  43. package/dist_ts/http/router/route-router.d.ts +108 -0
  44. package/dist_ts/http/router/route-router.js +393 -0
  45. package/dist_ts/index.d.ts +8 -2
  46. package/dist_ts/index.js +10 -3
  47. package/dist_ts/proxies/index.d.ts +7 -2
  48. package/dist_ts/proxies/index.js +10 -4
  49. package/dist_ts/proxies/network-proxy/certificate-manager.d.ts +21 -0
  50. package/dist_ts/proxies/network-proxy/certificate-manager.js +92 -1
  51. package/dist_ts/proxies/network-proxy/context-creator.d.ts +34 -0
  52. package/dist_ts/proxies/network-proxy/context-creator.js +108 -0
  53. package/dist_ts/proxies/network-proxy/function-cache.d.ts +90 -0
  54. package/dist_ts/proxies/network-proxy/function-cache.js +198 -0
  55. package/dist_ts/proxies/network-proxy/http-request-handler.d.ts +40 -0
  56. package/dist_ts/proxies/network-proxy/http-request-handler.js +256 -0
  57. package/dist_ts/proxies/network-proxy/http2-request-handler.d.ts +24 -0
  58. package/dist_ts/proxies/network-proxy/http2-request-handler.js +201 -0
  59. package/dist_ts/proxies/network-proxy/models/types.d.ts +73 -1
  60. package/dist_ts/proxies/network-proxy/models/types.js +242 -1
  61. package/dist_ts/proxies/network-proxy/network-proxy.d.ts +23 -20
  62. package/dist_ts/proxies/network-proxy/network-proxy.js +147 -60
  63. package/dist_ts/proxies/network-proxy/request-handler.d.ts +38 -5
  64. package/dist_ts/proxies/network-proxy/request-handler.js +584 -198
  65. package/dist_ts/proxies/network-proxy/security-manager.d.ts +65 -0
  66. package/dist_ts/proxies/network-proxy/security-manager.js +255 -0
  67. package/dist_ts/proxies/network-proxy/websocket-handler.d.ts +13 -2
  68. package/dist_ts/proxies/network-proxy/websocket-handler.js +238 -20
  69. package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
  70. package/dist_ts/proxies/smart-proxy/index.js +3 -3
  71. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -66
  72. package/dist_ts/proxies/smart-proxy/models/interfaces.js +5 -4
  73. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +173 -6
  74. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +20 -7
  75. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +49 -108
  76. package/dist_ts/proxies/smart-proxy/port-manager.d.ts +81 -0
  77. package/dist_ts/proxies/smart-proxy/port-manager.js +166 -0
  78. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +7 -5
  79. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +155 -160
  80. package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +9 -0
  81. package/dist_ts/proxies/smart-proxy/route-helpers/index.js +11 -0
  82. package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +5 -125
  83. package/dist_ts/proxies/smart-proxy/route-helpers.js +8 -195
  84. package/dist_ts/proxies/smart-proxy/route-manager.d.ts +14 -11
  85. package/dist_ts/proxies/smart-proxy/route-manager.js +81 -124
  86. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +101 -12
  87. package/dist_ts/proxies/smart-proxy/smart-proxy.js +178 -306
  88. package/dist_ts/proxies/smart-proxy/timeout-manager.js +3 -3
  89. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +12 -0
  90. package/dist_ts/proxies/smart-proxy/utils/index.js +19 -0
  91. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +240 -0
  92. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +451 -0
  93. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.d.ts +51 -0
  94. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.js +124 -0
  95. package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +131 -0
  96. package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +217 -0
  97. package/dist_ts/proxies/smart-proxy/utils/route-utils.d.ts +79 -0
  98. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +266 -0
  99. package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +73 -0
  100. package/dist_ts/proxies/smart-proxy/utils/route-validators.js +264 -0
  101. package/package.json +1 -1
  102. package/readme.md +241 -125
  103. package/readme.plan.md +73 -286
  104. package/ts/00_commitinfo_data.ts +1 -1
  105. package/ts/certificate/index.ts +17 -9
  106. package/ts/certificate/models/certificate-types.ts +37 -16
  107. package/ts/certificate/providers/cert-provisioner.ts +247 -54
  108. package/ts/core/models/index.ts +2 -0
  109. package/ts/core/models/route-context.ts +113 -0
  110. package/ts/core/models/socket-augmentation.ts +33 -0
  111. package/ts/core/utils/event-system.ts +376 -0
  112. package/ts/core/utils/index.ts +7 -0
  113. package/ts/core/utils/route-manager.ts +489 -0
  114. package/ts/core/utils/route-utils.ts +312 -0
  115. package/ts/core/utils/security-utils.ts +309 -0
  116. package/ts/core/utils/shared-security-manager.ts +333 -0
  117. package/ts/core/utils/template-utils.ts +124 -0
  118. package/ts/core/utils/websocket-utils.ts +81 -0
  119. package/ts/forwarding/config/forwarding-types.ts +79 -107
  120. package/ts/forwarding/config/index.ts +4 -2
  121. package/ts/forwarding/handlers/base-handler.ts +4 -2
  122. package/ts/forwarding/index.ts +3 -2
  123. package/ts/http/models/http-types.ts +0 -1
  124. package/ts/http/port80/acme-interfaces.ts +84 -0
  125. package/ts/http/port80/port80-handler.ts +61 -15
  126. package/ts/http/router/index.ts +8 -1
  127. package/ts/http/router/route-router.ts +482 -0
  128. package/ts/index.ts +14 -2
  129. package/ts/proxies/index.ts +12 -3
  130. package/ts/proxies/network-proxy/certificate-manager.ts +114 -10
  131. package/ts/proxies/network-proxy/context-creator.ts +145 -0
  132. package/ts/proxies/network-proxy/function-cache.ts +259 -0
  133. package/ts/proxies/network-proxy/http-request-handler.ts +330 -0
  134. package/ts/proxies/network-proxy/http2-request-handler.ts +255 -0
  135. package/ts/proxies/network-proxy/models/types.ts +312 -1
  136. package/ts/proxies/network-proxy/network-proxy.ts +195 -86
  137. package/ts/proxies/network-proxy/request-handler.ts +698 -246
  138. package/ts/proxies/network-proxy/security-manager.ts +298 -0
  139. package/ts/proxies/network-proxy/websocket-handler.ts +276 -33
  140. package/ts/proxies/smart-proxy/index.ts +2 -12
  141. package/ts/proxies/smart-proxy/models/interfaces.ts +13 -67
  142. package/ts/proxies/smart-proxy/models/route-types.ts +223 -25
  143. package/ts/proxies/smart-proxy/network-proxy-bridge.ts +57 -123
  144. package/ts/proxies/smart-proxy/port-manager.ts +195 -0
  145. package/ts/proxies/smart-proxy/route-connection-handler.ts +191 -225
  146. package/ts/proxies/smart-proxy/route-manager.ts +101 -144
  147. package/ts/proxies/smart-proxy/smart-proxy.ts +206 -377
  148. package/ts/proxies/smart-proxy/timeout-manager.ts +2 -2
  149. package/ts/proxies/smart-proxy/utils/index.ts +40 -0
  150. package/ts/proxies/smart-proxy/utils/route-helpers.ts +621 -0
  151. package/ts/proxies/smart-proxy/utils/route-migration-utils.ts +165 -0
  152. package/ts/proxies/smart-proxy/utils/route-patterns.ts +309 -0
  153. package/ts/proxies/smart-proxy/utils/route-utils.ts +330 -0
  154. package/ts/proxies/smart-proxy/utils/route-validators.ts +288 -0
  155. package/ts/forwarding/config/domain-config.ts +0 -28
  156. package/ts/forwarding/config/domain-manager.ts +0 -283
  157. package/ts/proxies/smart-proxy/connection-handler.ts +0 -1240
  158. package/ts/proxies/smart-proxy/domain-config-manager.ts +0 -441
  159. package/ts/proxies/smart-proxy/port-range-manager.ts +0 -211
  160. package/ts/proxies/smart-proxy/route-helpers.ts +0 -344
@@ -1,13 +1,21 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import { NetworkProxy } from '../network-proxy/index.js';
3
3
  import { Port80Handler } from '../../http/port80/port80-handler.js';
4
- import { Port80HandlerEvents } from '../../core/models/common-types.js';
5
4
  import { subscribeToPort80Handler } from '../../core/utils/event-utils.js';
6
5
  import type { ICertificateData } from '../../certificate/models/certificate-types.js';
7
- import type { IConnectionRecord, ISmartProxyOptions, IDomainConfig } from './models/interfaces.js';
6
+ import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js';
7
+ import type { IRouteConfig } from './models/route-types.js';
8
8
 
9
9
  /**
10
10
  * Manages NetworkProxy integration for TLS termination
11
+ *
12
+ * NetworkProxyBridge connects SmartProxy with NetworkProxy to handle TLS termination.
13
+ * It directly passes route configurations to NetworkProxy and manages the physical
14
+ * connection piping between SmartProxy and NetworkProxy for TLS termination.
15
+ *
16
+ * It is used by SmartProxy for routes that have:
17
+ * - TLS mode of 'terminate' or 'terminate-and-reencrypt'
18
+ * - Certificate set to 'auto' or custom certificate
11
19
  */
12
20
  export class NetworkProxyBridge {
13
21
  private networkProxy: NetworkProxy | null = null;
@@ -40,7 +48,7 @@ export class NetworkProxyBridge {
40
48
  */
41
49
  public async initialize(): Promise<void> {
42
50
  if (!this.networkProxy && this.settings.useNetworkProxy && this.settings.useNetworkProxy.length > 0) {
43
- // Configure NetworkProxy options based on PortProxy settings
51
+ // Configure NetworkProxy options based on SmartProxy settings
44
52
  const networkProxyOptions: any = {
45
53
  port: this.settings.networkProxyPort!,
46
54
  portProxyIntegration: true,
@@ -48,7 +56,6 @@ export class NetworkProxyBridge {
48
56
  useExternalPort80Handler: !!this.port80Handler // Use Port80Handler if available
49
57
  };
50
58
 
51
-
52
59
  this.networkProxy = new NetworkProxy(networkProxyOptions);
53
60
 
54
61
  console.log(`Initialized NetworkProxy on port ${this.settings.networkProxyPort}`);
@@ -58,8 +65,8 @@ export class NetworkProxyBridge {
58
65
  this.networkProxy.setExternalPort80Handler(this.port80Handler);
59
66
  }
60
67
 
61
- // Convert and apply domain configurations to NetworkProxy
62
- await this.syncDomainConfigsToNetworkProxy();
68
+ // Apply route configurations to NetworkProxy
69
+ await this.syncRoutesToNetworkProxy(this.settings.routes || []);
63
70
  }
64
71
  }
65
72
 
@@ -71,29 +78,8 @@ export class NetworkProxyBridge {
71
78
 
72
79
  console.log(`Received certificate for ${data.domain} from Port80Handler, updating NetworkProxy`);
73
80
 
74
- try {
75
- // Find existing config for this domain
76
- const existingConfigs = this.networkProxy.getProxyConfigs()
77
- .filter(config => config.hostName === data.domain);
78
-
79
- if (existingConfigs.length > 0) {
80
- // Update existing configs with new certificate
81
- for (const config of existingConfigs) {
82
- config.privateKey = data.privateKey;
83
- config.publicKey = data.certificate;
84
- }
85
-
86
- // Apply updated configs
87
- this.networkProxy.updateProxyConfigs(existingConfigs)
88
- .then(() => console.log(`Updated certificate for ${data.domain} in NetworkProxy`))
89
- .catch(err => console.log(`Error updating certificate in NetworkProxy: ${err}`));
90
- } else {
91
- // Create a new config for this domain
92
- console.log(`No existing config found for ${data.domain}, creating new config in NetworkProxy`);
93
- }
94
- } catch (err) {
95
- console.log(`Error handling certificate event: ${err}`);
96
- }
81
+ // Apply certificate directly to NetworkProxy
82
+ this.networkProxy.updateCertificate(data.domain, data.certificate, data.privateKey);
97
83
  }
98
84
 
99
85
  /**
@@ -104,7 +90,9 @@ export class NetworkProxyBridge {
104
90
  console.log(`NetworkProxy not initialized: cannot apply external certificate for ${data.domain}`);
105
91
  return;
106
92
  }
107
- this.handleCertificateEvent(data);
93
+
94
+ // Apply certificate directly to NetworkProxy
95
+ this.networkProxy.updateCertificate(data.domain, data.certificate, data.privateKey);
108
96
  }
109
97
 
110
98
  /**
@@ -146,37 +134,6 @@ export class NetworkProxyBridge {
146
134
  }
147
135
  }
148
136
 
149
- /**
150
- * Register domains with Port80Handler
151
- */
152
- public registerDomainsWithPort80Handler(domains: string[]): void {
153
- if (!this.port80Handler) {
154
- console.log('Cannot register domains - Port80Handler not initialized');
155
- return;
156
- }
157
-
158
- for (const domain of domains) {
159
- // Skip wildcards
160
- if (domain.includes('*')) {
161
- console.log(`Skipping wildcard domain for ACME: ${domain}`);
162
- continue;
163
- }
164
-
165
- // Register the domain
166
- try {
167
- this.port80Handler.addDomain({
168
- domainName: domain,
169
- sslRedirect: true,
170
- acmeMaintenance: true
171
- });
172
-
173
- console.log(`Registered domain with Port80Handler: ${domain}`);
174
- } catch (err) {
175
- console.log(`Error registering domain ${domain} with Port80Handler: ${err}`);
176
- }
177
- }
178
- }
179
-
180
137
  /**
181
138
  * Forwards a TLS connection to a NetworkProxy for handling
182
139
  */
@@ -241,7 +198,6 @@ export class NetworkProxyBridge {
241
198
  socket.pipe(proxySocket);
242
199
  proxySocket.pipe(socket);
243
200
 
244
- // Update activity on data transfer (caller should handle this)
245
201
  if (this.settings.enableDetailedLogging) {
246
202
  console.log(`[${connectionId}] TLS connection successfully forwarded to NetworkProxy`);
247
203
  }
@@ -249,76 +205,44 @@ export class NetworkProxyBridge {
249
205
  }
250
206
 
251
207
  /**
252
- * Synchronizes domain configurations to NetworkProxy
208
+ * Synchronizes routes to NetworkProxy
209
+ *
210
+ * This method directly passes route configurations to NetworkProxy without any
211
+ * intermediate conversion. NetworkProxy natively understands route configurations.
212
+ *
213
+ * @param routes The route configurations to sync to NetworkProxy
253
214
  */
254
- public async syncDomainConfigsToNetworkProxy(): Promise<void> {
215
+ public async syncRoutesToNetworkProxy(routes: IRouteConfig[]): Promise<void> {
255
216
  if (!this.networkProxy) {
256
217
  console.log('Cannot sync configurations - NetworkProxy not initialized');
257
218
  return;
258
219
  }
259
220
 
260
221
  try {
261
- // Get SSL certificates from assets
262
- // Import fs directly since it's not in plugins
263
- const fs = await import('fs');
264
-
265
- let certPair;
266
- try {
267
- certPair = {
268
- key: fs.readFileSync('assets/certs/key.pem', 'utf8'),
269
- cert: fs.readFileSync('assets/certs/cert.pem', 'utf8'),
270
- };
271
- } catch (certError) {
272
- console.log(`Warning: Could not read default certificates: ${certError}`);
273
- console.log(
274
- 'Using empty certificate placeholders - ACME will generate proper certificates if enabled'
222
+ // Filter only routes that are applicable to NetworkProxy (TLS termination)
223
+ const networkProxyRoutes = routes.filter(route => {
224
+ return (
225
+ route.action.type === 'forward' &&
226
+ route.action.tls &&
227
+ (route.action.tls.mode === 'terminate' || route.action.tls.mode === 'terminate-and-reencrypt')
275
228
  );
229
+ });
276
230
 
277
- // Use empty placeholders - NetworkProxy will use its internal defaults
278
- // or ACME will generate proper ones if enabled
279
- certPair = {
280
- key: '',
281
- cert: '',
282
- };
283
- }
284
-
285
- // Convert domain configs to NetworkProxy configs
286
- const proxyConfigs = this.networkProxy.convertSmartProxyConfigs(
287
- this.settings.domainConfigs,
288
- certPair
289
- );
290
-
291
- // Log ACME-eligible domains
292
- const acmeEnabled = !!this.settings.acme?.enabled;
293
- if (acmeEnabled) {
294
- const acmeEligibleDomains = proxyConfigs
295
- .filter((config) => !config.hostName.includes('*')) // Exclude wildcards
296
- .map((config) => config.hostName);
297
-
298
- if (acmeEligibleDomains.length > 0) {
299
- console.log(`Domains eligible for ACME certificates: ${acmeEligibleDomains.join(', ')}`);
300
-
301
- // Register these domains with Port80Handler if available
302
- if (this.port80Handler) {
303
- this.registerDomainsWithPort80Handler(acmeEligibleDomains);
304
- }
305
- } else {
306
- console.log('No domains eligible for ACME certificates found in configuration');
307
- }
308
- }
309
-
310
- // Update NetworkProxy with the converted configs
311
- await this.networkProxy.updateProxyConfigs(proxyConfigs);
312
- console.log(`Successfully synchronized ${proxyConfigs.length} domain configurations to NetworkProxy`);
231
+ // Pass routes directly to NetworkProxy
232
+ await this.networkProxy.updateRouteConfigs(networkProxyRoutes);
233
+ console.log(`Synced ${networkProxyRoutes.length} routes directly to NetworkProxy`);
313
234
  } catch (err) {
314
- console.log(`Failed to sync configurations: ${err}`);
235
+ console.log(`Error syncing routes to NetworkProxy: ${err}`);
315
236
  }
316
237
  }
317
238
 
318
239
  /**
319
240
  * Request a certificate for a specific domain
241
+ *
242
+ * @param domain The domain to request a certificate for
243
+ * @param routeName Optional route name to associate with this certificate
320
244
  */
321
- public async requestCertificate(domain: string): Promise<boolean> {
245
+ public async requestCertificate(domain: string, routeName?: string): Promise<boolean> {
322
246
  // Delegate to Port80Handler if available
323
247
  if (this.port80Handler) {
324
248
  try {
@@ -328,14 +252,24 @@ export class NetworkProxyBridge {
328
252
  console.log(`Certificate already exists for ${domain}`);
329
253
  return true;
330
254
  }
331
-
332
- // Register the domain for certificate issuance
333
- this.port80Handler.addDomain({
255
+
256
+ // Build the domain options
257
+ const domainOptions: any = {
334
258
  domainName: domain,
335
259
  sslRedirect: true,
336
- acmeMaintenance: true
337
- });
338
-
260
+ acmeMaintenance: true,
261
+ };
262
+
263
+ // Add route reference if available
264
+ if (routeName) {
265
+ domainOptions.routeReference = {
266
+ routeName
267
+ };
268
+ }
269
+
270
+ // Register the domain for certificate issuance
271
+ this.port80Handler.addDomain(domainOptions);
272
+
339
273
  console.log(`Domain ${domain} registered for certificate issuance`);
340
274
  return true;
341
275
  } catch (err) {
@@ -343,7 +277,7 @@ export class NetworkProxyBridge {
343
277
  return false;
344
278
  }
345
279
  }
346
-
280
+
347
281
  // Fall back to NetworkProxy if Port80Handler is not available
348
282
  if (!this.networkProxy) {
349
283
  console.log('Cannot request certificate - NetworkProxy not initialized');
@@ -0,0 +1,195 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { ISmartProxyOptions } from './models/interfaces.js';
3
+ import { RouteConnectionHandler } from './route-connection-handler.js';
4
+
5
+ /**
6
+ * PortManager handles the dynamic creation and removal of port listeners
7
+ *
8
+ * This class provides methods to add and remove listening ports at runtime,
9
+ * allowing SmartProxy to adapt to configuration changes without requiring
10
+ * a full restart.
11
+ */
12
+ export class PortManager {
13
+ private servers: Map<number, plugins.net.Server> = new Map();
14
+ private settings: ISmartProxyOptions;
15
+ private routeConnectionHandler: RouteConnectionHandler;
16
+ private isShuttingDown: boolean = false;
17
+
18
+ /**
19
+ * Create a new PortManager
20
+ *
21
+ * @param settings The SmartProxy settings
22
+ * @param routeConnectionHandler The handler for new connections
23
+ */
24
+ constructor(
25
+ settings: ISmartProxyOptions,
26
+ routeConnectionHandler: RouteConnectionHandler
27
+ ) {
28
+ this.settings = settings;
29
+ this.routeConnectionHandler = routeConnectionHandler;
30
+ }
31
+
32
+ /**
33
+ * Start listening on a specific port
34
+ *
35
+ * @param port The port number to listen on
36
+ * @returns Promise that resolves when the server is listening or rejects on error
37
+ */
38
+ public async addPort(port: number): Promise<void> {
39
+ // Check if we're already listening on this port
40
+ if (this.servers.has(port)) {
41
+ console.log(`PortManager: Already listening on port ${port}`);
42
+ return;
43
+ }
44
+
45
+ // Create a server for this port
46
+ const server = plugins.net.createServer((socket) => {
47
+ // Check if shutting down
48
+ if (this.isShuttingDown) {
49
+ socket.end();
50
+ socket.destroy();
51
+ return;
52
+ }
53
+
54
+ // Delegate to route connection handler
55
+ this.routeConnectionHandler.handleConnection(socket);
56
+ }).on('error', (err: Error) => {
57
+ console.log(`Server Error on port ${port}: ${err.message}`);
58
+ });
59
+
60
+ // Start listening on the port
61
+ return new Promise<void>((resolve, reject) => {
62
+ server.listen(port, () => {
63
+ const isNetworkProxyPort = this.settings.useNetworkProxy?.includes(port);
64
+ console.log(
65
+ `SmartProxy -> OK: Now listening on port ${port}${
66
+ isNetworkProxyPort ? ' (NetworkProxy forwarding enabled)' : ''
67
+ }`
68
+ );
69
+
70
+ // Store the server reference
71
+ this.servers.set(port, server);
72
+ resolve();
73
+ }).on('error', (err) => {
74
+ console.log(`Failed to listen on port ${port}: ${err.message}`);
75
+ reject(err);
76
+ });
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Stop listening on a specific port
82
+ *
83
+ * @param port The port to stop listening on
84
+ * @returns Promise that resolves when the server is closed
85
+ */
86
+ public async removePort(port: number): Promise<void> {
87
+ // Get the server for this port
88
+ const server = this.servers.get(port);
89
+ if (!server) {
90
+ console.log(`PortManager: Not listening on port ${port}`);
91
+ return;
92
+ }
93
+
94
+ // Close the server
95
+ return new Promise<void>((resolve) => {
96
+ server.close((err) => {
97
+ if (err) {
98
+ console.log(`Error closing server on port ${port}: ${err.message}`);
99
+ } else {
100
+ console.log(`SmartProxy -> Stopped listening on port ${port}`);
101
+ }
102
+
103
+ // Remove the server reference
104
+ this.servers.delete(port);
105
+ resolve();
106
+ });
107
+ });
108
+ }
109
+
110
+ /**
111
+ * Add multiple ports at once
112
+ *
113
+ * @param ports Array of ports to add
114
+ * @returns Promise that resolves when all servers are listening
115
+ */
116
+ public async addPorts(ports: number[]): Promise<void> {
117
+ const uniquePorts = [...new Set(ports)];
118
+ await Promise.all(uniquePorts.map(port => this.addPort(port)));
119
+ }
120
+
121
+ /**
122
+ * Remove multiple ports at once
123
+ *
124
+ * @param ports Array of ports to remove
125
+ * @returns Promise that resolves when all servers are closed
126
+ */
127
+ public async removePorts(ports: number[]): Promise<void> {
128
+ const uniquePorts = [...new Set(ports)];
129
+ await Promise.all(uniquePorts.map(port => this.removePort(port)));
130
+ }
131
+
132
+ /**
133
+ * Update listening ports to match the provided list
134
+ *
135
+ * This will add any ports that aren't currently listening,
136
+ * and remove any ports that are no longer needed.
137
+ *
138
+ * @param ports Array of ports that should be listening
139
+ * @returns Promise that resolves when all operations are complete
140
+ */
141
+ public async updatePorts(ports: number[]): Promise<void> {
142
+ const targetPorts = new Set(ports);
143
+ const currentPorts = new Set(this.servers.keys());
144
+
145
+ // Find ports to add and remove
146
+ const portsToAdd = ports.filter(port => !currentPorts.has(port));
147
+ const portsToRemove = Array.from(currentPorts).filter(port => !targetPorts.has(port));
148
+
149
+ // Log the changes
150
+ if (portsToAdd.length > 0) {
151
+ console.log(`PortManager: Adding new listeners for ports: ${portsToAdd.join(', ')}`);
152
+ }
153
+
154
+ if (portsToRemove.length > 0) {
155
+ console.log(`PortManager: Removing listeners for ports: ${portsToRemove.join(', ')}`);
156
+ }
157
+
158
+ // Add and remove ports
159
+ await this.removePorts(portsToRemove);
160
+ await this.addPorts(portsToAdd);
161
+ }
162
+
163
+ /**
164
+ * Get all ports that are currently listening
165
+ *
166
+ * @returns Array of port numbers
167
+ */
168
+ public getListeningPorts(): number[] {
169
+ return Array.from(this.servers.keys());
170
+ }
171
+
172
+ /**
173
+ * Mark the port manager as shutting down
174
+ */
175
+ public setShuttingDown(isShuttingDown: boolean): void {
176
+ this.isShuttingDown = isShuttingDown;
177
+ }
178
+
179
+ /**
180
+ * Close all listening servers
181
+ *
182
+ * @returns Promise that resolves when all servers are closed
183
+ */
184
+ public async closeAll(): Promise<void> {
185
+ const allPorts = Array.from(this.servers.keys());
186
+ await this.removePorts(allPorts);
187
+ }
188
+
189
+ /**
190
+ * Get all server instances (for testing or debugging)
191
+ */
192
+ public getServers(): Map<number, plugins.net.Server> {
193
+ return new Map(this.servers);
194
+ }
195
+ }