@push.rocks/smartproxy 19.6.2 → 19.6.7
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.
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +4 -7
- package/dist_ts/proxies/smart-proxy/connection-manager.js +22 -22
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +4 -3
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +9 -9
- package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +68 -56
- package/dist_ts/proxies/smart-proxy/metrics-collector.js +226 -176
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -0
- package/dist_ts/proxies/smart-proxy/models/metrics-types.d.ts +94 -48
- package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +4 -4
- package/dist_ts/proxies/smart-proxy/nftables-manager.js +6 -6
- package/dist_ts/proxies/smart-proxy/port-manager.d.ts +4 -7
- package/dist_ts/proxies/smart-proxy/port-manager.js +6 -9
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -15
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +128 -128
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +3 -3
- package/dist_ts/proxies/smart-proxy/security-manager.js +9 -9
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +20 -13
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +16 -13
- package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +36 -0
- package/dist_ts/proxies/smart-proxy/throughput-tracker.js +117 -0
- package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +4 -3
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +16 -16
- package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +3 -3
- package/dist_ts/proxies/smart-proxy/tls-manager.js +12 -12
- package/package.json +8 -17
- package/readme.hints.md +0 -897
- package/readme.md +960 -54
- package/readme.plan.md +301 -562
- package/ts/proxies/smart-proxy/connection-manager.ts +23 -21
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +9 -8
- package/ts/proxies/smart-proxy/metrics-collector.ts +277 -189
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -0
- package/ts/proxies/smart-proxy/models/metrics-types.ts +93 -41
- package/ts/proxies/smart-proxy/nftables-manager.ts +5 -5
- package/ts/proxies/smart-proxy/port-manager.ts +6 -14
- package/ts/proxies/smart-proxy/route-connection-handler.ts +136 -136
- package/ts/proxies/smart-proxy/security-manager.ts +8 -8
- package/ts/proxies/smart-proxy/smart-proxy.ts +26 -35
- package/ts/proxies/smart-proxy/throughput-tracker.ts +144 -0
- package/ts/proxies/smart-proxy/timeout-manager.ts +16 -15
- package/ts/proxies/smart-proxy/tls-manager.ts +11 -11
- package/readme.connections.md +0 -724
- package/readme.delete.md +0 -187
- package/readme.memory-leaks-fixed.md +0 -45
- package/readme.metrics.md +0 -591
- package/readme.monitoring.md +0 -202
- package/readme.proxy-chain-summary.md +0 -112
- package/readme.proxy-protocol-example.md +0 -462
- package/readme.proxy-protocol.md +0 -415
- package/readme.routing.md +0 -341
- package/readme.websocket-keepalive-config.md +0 -140
- package/readme.websocket-keepalive-fix.md +0 -63
package/readme.plan.md
CHANGED
|
@@ -1,625 +1,364 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
## ⚠️ CRITICAL: Implementation Order
|
|
4
|
-
|
|
5
|
-
**Phase 1 (ProxyProtocolSocket/WrappedSocket) MUST be completed first!**
|
|
6
|
-
|
|
7
|
-
The ProxyProtocolSocket class is the foundation that enables all PROXY protocol functionality. No protocol parsing or integration can happen until this wrapper class is fully implemented and tested.
|
|
8
|
-
|
|
9
|
-
1. **FIRST**: Implement ProxyProtocolSocket (the WrappedSocket)
|
|
10
|
-
2. **THEN**: Add PROXY protocol parser
|
|
11
|
-
3. **THEN**: Integrate with connection handlers
|
|
12
|
-
4. **FINALLY**: Add security and validation
|
|
1
|
+
# SmartProxy Metrics Improvement Plan
|
|
13
2
|
|
|
14
3
|
## Overview
|
|
15
|
-
Implement PROXY protocol support in SmartProxy to preserve client IP information through proxy chains, solving the connection limit accumulation issue where inner proxies see all connections as coming from the outer proxy's IP.
|
|
16
4
|
|
|
17
|
-
|
|
18
|
-
- In proxy chains, the inner proxy sees all connections from the outer proxy's IP
|
|
19
|
-
- This causes the inner proxy to hit per-IP connection limits (default: 100)
|
|
20
|
-
- Results in connection rejections while outer proxy accumulates connections
|
|
5
|
+
The current `getThroughputRate()` implementation calculates cumulative throughput over a 60-second window rather than providing an actual rate, making metrics misleading for monitoring systems. This plan outlines a comprehensive redesign of the metrics system to provide accurate, time-series based metrics suitable for production monitoring.
|
|
21
6
|
|
|
22
|
-
##
|
|
7
|
+
## 1. Core Issues with Current Implementation
|
|
23
8
|
|
|
24
|
-
|
|
9
|
+
- **Cumulative vs Rate**: Current method accumulates all bytes from connections in the last minute rather than calculating actual throughput rate
|
|
10
|
+
- **No Time-Series Data**: Cannot track throughput changes over time
|
|
11
|
+
- **Inaccurate Estimates**: Attempting to estimate rates for older connections is fundamentally flawed
|
|
12
|
+
- **No Sliding Windows**: Cannot provide different time window views (1s, 10s, 60s, etc.)
|
|
13
|
+
- **Limited Granularity**: Only provides a single 60-second view
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
- Support PROXY protocol v1 (text format) initially
|
|
28
|
-
- Parse incoming PROXY headers to extract:
|
|
29
|
-
- Real client IP address
|
|
30
|
-
- Real client port
|
|
31
|
-
- Proxy IP address
|
|
32
|
-
- Proxy port
|
|
33
|
-
- Protocol (TCP4/TCP6)
|
|
15
|
+
## 2. Proposed Architecture
|
|
34
16
|
|
|
35
|
-
|
|
36
|
-
- Add ability to send PROXY protocol headers when forwarding connections
|
|
37
|
-
- Configurable per route or target
|
|
38
|
-
|
|
39
|
-
#### 1.3 Trusted Proxy IPs
|
|
40
|
-
- New `proxyIPs` array in SmartProxy options
|
|
41
|
-
- Auto-enable PROXY protocol acceptance for connections from these IPs
|
|
42
|
-
- Reject PROXY protocol from untrusted sources (security)
|
|
43
|
-
|
|
44
|
-
### 2. Configuration Schema
|
|
17
|
+
### A. Time-Series Throughput Tracking
|
|
45
18
|
|
|
46
19
|
```typescript
|
|
47
|
-
interface
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
proxyIPs?: string[];
|
|
52
|
-
|
|
53
|
-
// Global option to accept PROXY protocol (defaults based on proxyIPs)
|
|
54
|
-
acceptProxyProtocol?: boolean;
|
|
55
|
-
|
|
56
|
-
// Global option to send PROXY protocol to all targets
|
|
57
|
-
sendProxyProtocol?: boolean;
|
|
20
|
+
interface IThroughputSample {
|
|
21
|
+
timestamp: number;
|
|
22
|
+
bytesIn: number;
|
|
23
|
+
bytesOut: number;
|
|
58
24
|
}
|
|
59
25
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### 3. Implementation Steps
|
|
69
|
-
|
|
70
|
-
#### IMPORTANT: Phase 1 Must Be Completed First
|
|
71
|
-
The `ProxyProtocolSocket` (WrappedSocket) is the foundation for all PROXY protocol functionality. This wrapper class must be implemented and integrated BEFORE any PROXY protocol parsing can begin.
|
|
72
|
-
|
|
73
|
-
#### Phase 1: ProxyProtocolSocket (WrappedSocket) Foundation - ✅ COMPLETED (v19.5.19)
|
|
74
|
-
This phase creates the socket wrapper infrastructure that all subsequent phases depend on.
|
|
75
|
-
|
|
76
|
-
1. **Create WrappedSocket class** in `ts/core/models/wrapped-socket.ts` ✅
|
|
77
|
-
- Used JavaScript Proxy pattern instead of EventEmitter (avoids infinite loops)
|
|
78
|
-
- Properties for real client IP and port
|
|
79
|
-
- Transparent getters that return real or socket IP/port
|
|
80
|
-
- All socket methods/properties delegated via Proxy
|
|
81
|
-
|
|
82
|
-
2. **Implement core wrapper functionality** ✅
|
|
83
|
-
- Constructor accepts regular socket + optional metadata
|
|
84
|
-
- `remoteAddress` getter returns real IP or falls back to socket IP
|
|
85
|
-
- `remotePort` getter returns real port or falls back to socket port
|
|
86
|
-
- `isFromTrustedProxy` property to check if it has real client info
|
|
87
|
-
- `setProxyInfo()` method to update real client details
|
|
88
|
-
|
|
89
|
-
3. **Update ConnectionManager to handle wrapped sockets** ✅
|
|
90
|
-
- Accept either `net.Socket` or `WrappedSocket`
|
|
91
|
-
- Created `getUnderlyingSocket()` helper for socket utilities
|
|
92
|
-
- All socket utility functions extract underlying socket
|
|
93
|
-
|
|
94
|
-
4. **Integration completed** ✅
|
|
95
|
-
- All incoming sockets wrapped in RouteConnectionHandler
|
|
96
|
-
- Socket forwarding verified working with wrapped sockets
|
|
97
|
-
- Type safety maintained with index signature
|
|
98
|
-
|
|
99
|
-
**Deliverables**: ✅ Working WrappedSocket that can wrap any socket and provide transparent access to client info.
|
|
100
|
-
|
|
101
|
-
#### Phase 2: PROXY Protocol Parser - ✅ COMPLETED (v19.5.21)
|
|
102
|
-
Only after WrappedSocket is working can we add protocol parsing.
|
|
103
|
-
|
|
104
|
-
1. ✅ Created `ProxyProtocolParser` class in `ts/core/utils/proxy-protocol.ts`
|
|
105
|
-
2. ✅ Implemented v1 text format parsing with full validation
|
|
106
|
-
3. ✅ Added comprehensive error handling and IP validation
|
|
107
|
-
4. ✅ Integrated parser to work WITH WrappedSocket in RouteConnectionHandler
|
|
108
|
-
|
|
109
|
-
**Deliverables**: ✅ Working PROXY protocol v1 parser that validates headers, extracts client info, and handles both TCP4 and TCP6 protocols.
|
|
110
|
-
|
|
111
|
-
#### Phase 3: Connection Handler Integration - ✅ COMPLETED (v19.5.21)
|
|
112
|
-
1. ✅ Modify `RouteConnectionHandler` to create WrappedSocket for all connections
|
|
113
|
-
2. ✅ Check if connection is from trusted proxy IP
|
|
114
|
-
3. ✅ If trusted, attempt to parse PROXY protocol header
|
|
115
|
-
4. ✅ Update wrapped socket with real client info
|
|
116
|
-
5. ✅ Continue normal connection handling with wrapped socket
|
|
117
|
-
|
|
118
|
-
**Deliverables**: ✅ RouteConnectionHandler now parses PROXY protocol from trusted proxies and updates connection records with real client info.
|
|
119
|
-
|
|
120
|
-
#### Phase 4: Outbound PROXY Protocol - ✅ COMPLETED (v19.5.21)
|
|
121
|
-
1. ✅ Add PROXY header generation in `setupDirectConnection`
|
|
122
|
-
2. ✅ Make it configurable per route via `sendProxyProtocol` option
|
|
123
|
-
3. ✅ Send header immediately after TCP connection
|
|
124
|
-
4. ✅ Added remotePort tracking to connection records
|
|
125
|
-
|
|
126
|
-
**Deliverables**: ✅ SmartProxy can now send PROXY protocol headers to backend servers when configured, preserving client IP through proxy chains.
|
|
127
|
-
|
|
128
|
-
#### Phase 5: Security & Validation - FINAL PHASE
|
|
129
|
-
1. Validate PROXY headers strictly
|
|
130
|
-
2. Reject malformed headers
|
|
131
|
-
3. Only accept from trusted IPs
|
|
132
|
-
4. Add rate limiting for PROXY protocol parsing
|
|
133
|
-
|
|
134
|
-
### 4. Design Decision: Socket Wrapper Architecture
|
|
135
|
-
|
|
136
|
-
#### Option A: Minimal Single Socket Wrapper
|
|
137
|
-
- **Scope**: Wraps individual sockets with metadata
|
|
138
|
-
- **Use Case**: PROXY protocol support with minimal refactoring
|
|
139
|
-
- **Pros**: Simple, low risk, easy migration
|
|
140
|
-
- **Cons**: Still need separate connection management
|
|
141
|
-
|
|
142
|
-
#### Option B: Comprehensive Connection Wrapper
|
|
143
|
-
- **Scope**: Manages socket pairs (incoming + outgoing) with all utilities
|
|
144
|
-
- **Use Case**: Complete connection lifecycle management
|
|
145
|
-
- **Pros**:
|
|
146
|
-
- Encapsulates all socket utilities (forwarding, cleanup, backpressure)
|
|
147
|
-
- Single object represents entire connection
|
|
148
|
-
- Cleaner API for connection handling
|
|
149
|
-
- **Cons**:
|
|
150
|
-
- Major architectural change
|
|
151
|
-
- Higher implementation risk
|
|
152
|
-
- More complex migration
|
|
153
|
-
|
|
154
|
-
#### Recommendation
|
|
155
|
-
Start with **Option A** (ProxyProtocolSocket) for immediate PROXY protocol support, then evaluate Option B based on:
|
|
156
|
-
- Performance impact of additional abstraction
|
|
157
|
-
- Code simplification benefits
|
|
158
|
-
- Team comfort with architectural change
|
|
159
|
-
|
|
160
|
-
### 5. Code Implementation Details
|
|
161
|
-
|
|
162
|
-
#### 5.1 ProxyProtocolSocket (WrappedSocket) - PHASE 1 IMPLEMENTATION
|
|
163
|
-
This is the foundational wrapper class that MUST be implemented first. It wraps a regular socket and provides transparent access to the real client IP/port.
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
// ts/core/models/proxy-protocol-socket.ts
|
|
167
|
-
import { EventEmitter } from 'events';
|
|
168
|
-
import * as plugins from '../../../plugins.js';
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* ProxyProtocolSocket wraps a regular net.Socket to provide transparent access
|
|
172
|
-
* to the real client IP and port when behind a proxy using PROXY protocol.
|
|
173
|
-
*
|
|
174
|
-
* This is the FOUNDATION for all PROXY protocol support and must be implemented
|
|
175
|
-
* before any protocol parsing can occur.
|
|
176
|
-
*/
|
|
177
|
-
export class ProxyProtocolSocket extends EventEmitter {
|
|
178
|
-
private realClientIP?: string;
|
|
179
|
-
private realClientPort?: number;
|
|
26
|
+
class ThroughputTracker {
|
|
27
|
+
private samples: IThroughputSample[] = [];
|
|
28
|
+
private readonly MAX_SAMPLES = 3600; // 1 hour at 1 sample/second
|
|
29
|
+
private lastSampleTime: number = 0;
|
|
30
|
+
private accumulatedBytesIn: number = 0;
|
|
31
|
+
private accumulatedBytesOut: number = 0;
|
|
180
32
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
) {
|
|
186
|
-
super();
|
|
187
|
-
this.realClientIP = realClientIP;
|
|
188
|
-
this.realClientPort = realClientPort;
|
|
189
|
-
|
|
190
|
-
// Forward all socket events
|
|
191
|
-
this.forwardSocketEvents();
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Returns the real client IP if available, otherwise the socket's remote address
|
|
196
|
-
*/
|
|
197
|
-
get remoteAddress(): string | undefined {
|
|
198
|
-
return this.realClientIP || this.socket.remoteAddress;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Returns the real client port if available, otherwise the socket's remote port
|
|
203
|
-
*/
|
|
204
|
-
get remotePort(): number | undefined {
|
|
205
|
-
return this.realClientPort || this.socket.remotePort;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Indicates if this connection came through a trusted proxy
|
|
210
|
-
*/
|
|
211
|
-
get isFromTrustedProxy(): boolean {
|
|
212
|
-
return !!this.realClientIP;
|
|
33
|
+
// Called on every data transfer
|
|
34
|
+
public recordBytes(bytesIn: number, bytesOut: number): void {
|
|
35
|
+
this.accumulatedBytesIn += bytesIn;
|
|
36
|
+
this.accumulatedBytesOut += bytesOut;
|
|
213
37
|
}
|
|
214
38
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
this.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
destroy(error?: Error): this {
|
|
234
|
-
this.socket.destroy(error);
|
|
235
|
-
return this;
|
|
39
|
+
// Called periodically (every second)
|
|
40
|
+
public takeSample(): void {
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
|
|
43
|
+
// Record accumulated bytes since last sample
|
|
44
|
+
this.samples.push({
|
|
45
|
+
timestamp: now,
|
|
46
|
+
bytesIn: this.accumulatedBytesIn,
|
|
47
|
+
bytesOut: this.accumulatedBytesOut
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Reset accumulators
|
|
51
|
+
this.accumulatedBytesIn = 0;
|
|
52
|
+
this.accumulatedBytesOut = 0;
|
|
53
|
+
|
|
54
|
+
// Trim old samples
|
|
55
|
+
const cutoff = now - 3600000; // 1 hour
|
|
56
|
+
this.samples = this.samples.filter(s => s.timestamp > cutoff);
|
|
236
57
|
}
|
|
237
58
|
|
|
238
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
59
|
+
// Get rate over specified window
|
|
60
|
+
public getRate(windowSeconds: number): { bytesInPerSec: number; bytesOutPerSec: number } {
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
const windowStart = now - (windowSeconds * 1000);
|
|
63
|
+
|
|
64
|
+
const relevantSamples = this.samples.filter(s => s.timestamp > windowStart);
|
|
65
|
+
|
|
66
|
+
if (relevantSamples.length === 0) {
|
|
67
|
+
return { bytesInPerSec: 0, bytesOutPerSec: 0 };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const totalBytesIn = relevantSamples.reduce((sum, s) => sum + s.bytesIn, 0);
|
|
71
|
+
const totalBytesOut = relevantSamples.reduce((sum, s) => sum + s.bytesOut, 0);
|
|
72
|
+
|
|
73
|
+
const actualWindow = (now - relevantSamples[0].timestamp) / 1000;
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
bytesInPerSec: Math.round(totalBytesIn / actualWindow),
|
|
77
|
+
bytesOutPerSec: Math.round(totalBytesOut / actualWindow)
|
|
78
|
+
};
|
|
250
79
|
}
|
|
251
80
|
}
|
|
252
81
|
```
|
|
253
82
|
|
|
254
|
-
|
|
83
|
+
### B. Connection-Level Byte Tracking
|
|
255
84
|
|
|
256
|
-
#### 4.2 ProxyProtocolParser (new file)
|
|
257
85
|
```typescript
|
|
258
|
-
//
|
|
259
|
-
|
|
260
|
-
|
|
86
|
+
// In ConnectionRecord, add:
|
|
87
|
+
interface IConnectionRecord {
|
|
88
|
+
// ... existing fields ...
|
|
261
89
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
90
|
+
// Byte counters with timestamps
|
|
91
|
+
bytesReceivedHistory: Array<{ timestamp: number; bytes: number }>;
|
|
92
|
+
bytesSentHistory: Array<{ timestamp: number; bytes: number }>;
|
|
265
93
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
94
|
+
// For efficiency, could use circular buffer
|
|
95
|
+
lastBytesReceivedUpdate: number;
|
|
96
|
+
lastBytesSentUpdate: number;
|
|
269
97
|
}
|
|
270
98
|
```
|
|
271
99
|
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
// In handleConnection method
|
|
275
|
-
let wrappedSocket: ProxyProtocolSocket | plugins.net.Socket = socket;
|
|
100
|
+
### C. Enhanced Metrics Interface
|
|
276
101
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
102
|
+
```typescript
|
|
103
|
+
interface IMetrics {
|
|
104
|
+
// Connection metrics
|
|
105
|
+
connections: {
|
|
106
|
+
active(): number;
|
|
107
|
+
total(): number;
|
|
108
|
+
byRoute(): Map<string, number>;
|
|
109
|
+
byIP(): Map<string, number>;
|
|
110
|
+
topIPs(limit?: number): Array<{ ip: string; count: number }>;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Throughput metrics (bytes per second)
|
|
114
|
+
throughput: {
|
|
115
|
+
instant(): { in: number; out: number }; // Last 1 second
|
|
116
|
+
recent(): { in: number; out: number }; // Last 10 seconds
|
|
117
|
+
average(): { in: number; out: number }; // Last 60 seconds
|
|
118
|
+
custom(seconds: number): { in: number; out: number };
|
|
119
|
+
history(seconds: number): Array<{ timestamp: number; in: number; out: number }>;
|
|
120
|
+
byRoute(windowSeconds?: number): Map<string, { in: number; out: number }>;
|
|
121
|
+
byIP(windowSeconds?: number): Map<string, { in: number; out: number }>;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Request metrics
|
|
125
|
+
requests: {
|
|
126
|
+
perSecond(): number;
|
|
127
|
+
perMinute(): number;
|
|
128
|
+
total(): number;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Cumulative totals
|
|
132
|
+
totals: {
|
|
133
|
+
bytesIn(): number;
|
|
134
|
+
bytesOut(): number;
|
|
135
|
+
connections(): number;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Performance metrics
|
|
139
|
+
percentiles: {
|
|
140
|
+
connectionDuration(): { p50: number; p95: number; p99: number };
|
|
141
|
+
bytesTransferred(): {
|
|
142
|
+
in: { p50: number; p95: number; p99: number };
|
|
143
|
+
out: { p50: number; p95: number; p99: number };
|
|
144
|
+
};
|
|
145
|
+
};
|
|
280
146
|
}
|
|
147
|
+
```
|
|
281
148
|
|
|
282
|
-
|
|
283
|
-
|
|
149
|
+
## 3. Implementation Plan
|
|
150
|
+
|
|
151
|
+
### Current Status
|
|
152
|
+
- **Phase 1**: ~90% complete (core functionality implemented, tests need fixing)
|
|
153
|
+
- **Phase 2**: ~60% complete (main features done, percentiles pending)
|
|
154
|
+
- **Phase 3**: ~40% complete (basic optimizations in place)
|
|
155
|
+
- **Phase 4**: 0% complete (export formats not started)
|
|
156
|
+
|
|
157
|
+
### Phase 1: Core Throughput Tracking (Week 1)
|
|
158
|
+
- [x] Implement `ThroughputTracker` class
|
|
159
|
+
- [x] Integrate byte recording into socket data handlers
|
|
160
|
+
- [x] Add periodic sampling (1-second intervals)
|
|
161
|
+
- [x] Update `getThroughputRate()` to use time-series data (replaced with new clean API)
|
|
162
|
+
- [ ] Add unit tests for throughput tracking
|
|
163
|
+
|
|
164
|
+
### Phase 2: Enhanced Metrics (Week 2)
|
|
165
|
+
- [x] Add configurable time windows (1s, 10s, 60s, 5m, etc.)
|
|
166
|
+
- [ ] Implement percentile calculations
|
|
167
|
+
- [x] Add route-specific and IP-specific throughput tracking
|
|
168
|
+
- [x] Create historical data access methods
|
|
169
|
+
- [ ] Add integration tests
|
|
170
|
+
|
|
171
|
+
### Phase 3: Performance Optimization (Week 3)
|
|
172
|
+
- [x] Use circular buffers for efficiency
|
|
173
|
+
- [ ] Implement data aggregation for longer time windows
|
|
174
|
+
- [x] Add configurable retention periods
|
|
175
|
+
- [ ] Optimize memory usage
|
|
176
|
+
- [ ] Add performance benchmarks
|
|
177
|
+
|
|
178
|
+
### Phase 4: Export Formats (Week 4)
|
|
179
|
+
- [ ] Add Prometheus metric format with proper metric types
|
|
180
|
+
- [ ] Add StatsD format support
|
|
181
|
+
- [ ] Add JSON export with metadata
|
|
182
|
+
- [ ] Create OpenMetrics compatibility
|
|
183
|
+
- [ ] Add documentation and examples
|
|
184
|
+
|
|
185
|
+
## 4. Key Design Decisions
|
|
186
|
+
|
|
187
|
+
### A. Sampling Strategy
|
|
188
|
+
- **1-second samples** for fine-grained data
|
|
189
|
+
- **Aggregate to 1-minute** for longer retention
|
|
190
|
+
- **Keep 1 hour** of second-level data
|
|
191
|
+
- **Keep 24 hours** of minute-level data
|
|
192
|
+
|
|
193
|
+
### B. Memory Management
|
|
194
|
+
- **Circular buffers** for fixed memory usage
|
|
195
|
+
- **Configurable retention** periods
|
|
196
|
+
- **Lazy aggregation** for older data
|
|
197
|
+
- **Efficient data structures** (typed arrays for samples)
|
|
198
|
+
|
|
199
|
+
### C. Performance Considerations
|
|
200
|
+
- **Batch updates** during high throughput
|
|
201
|
+
- **Debounced calculations** for expensive metrics
|
|
202
|
+
- **Cached results** with TTL
|
|
203
|
+
- **Worker thread** option for heavy calculations
|
|
204
|
+
|
|
205
|
+
## 5. Configuration Options
|
|
284
206
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
207
|
+
```typescript
|
|
208
|
+
interface IMetricsConfig {
|
|
209
|
+
enabled: boolean;
|
|
210
|
+
|
|
211
|
+
// Sampling configuration
|
|
212
|
+
sampleIntervalMs: number; // Default: 1000 (1 second)
|
|
213
|
+
retentionSeconds: number; // Default: 3600 (1 hour)
|
|
214
|
+
|
|
215
|
+
// Performance tuning
|
|
216
|
+
enableDetailedTracking: boolean; // Per-connection byte history
|
|
217
|
+
enablePercentiles: boolean; // Calculate percentiles
|
|
218
|
+
cacheResultsMs: number; // Cache expensive calculations
|
|
219
|
+
|
|
220
|
+
// Export configuration
|
|
221
|
+
prometheusEnabled: boolean;
|
|
222
|
+
prometheusPath: string; // Default: /metrics
|
|
223
|
+
prometheusPrefix: string; // Default: smartproxy_
|
|
292
224
|
}
|
|
293
225
|
```
|
|
294
226
|
|
|
295
|
-
|
|
296
|
-
- Accept socket or ProxyProtocolSocket
|
|
297
|
-
- Use `socket.remoteAddress` getter for real client IP
|
|
298
|
-
- Transparent handling of both socket types
|
|
227
|
+
## 6. Example Usage
|
|
299
228
|
|
|
300
|
-
### 5. Configuration Examples
|
|
301
|
-
|
|
302
|
-
#### Basic Setup (IMPLEMENTED ✅)
|
|
303
229
|
```typescript
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
type: 'forward',
|
|
311
|
-
target: { host: '195.201.98.232', port: 443 },
|
|
312
|
-
sendProxyProtocol: true // Enable for this route
|
|
313
|
-
}
|
|
314
|
-
}]
|
|
230
|
+
const proxy = new SmartProxy({
|
|
231
|
+
metrics: {
|
|
232
|
+
enabled: true,
|
|
233
|
+
sampleIntervalMs: 1000,
|
|
234
|
+
enableDetailedTracking: true
|
|
235
|
+
}
|
|
315
236
|
});
|
|
316
237
|
|
|
317
|
-
//
|
|
318
|
-
const
|
|
319
|
-
proxyIPs: ['212.95.99.130'], // Outer proxy IP
|
|
320
|
-
acceptProxyProtocol: true, // Optional - defaults to true when proxyIPs is set
|
|
321
|
-
routes: [{
|
|
322
|
-
name: 'to-backend',
|
|
323
|
-
match: { ports: 443 },
|
|
324
|
-
action: {
|
|
325
|
-
type: 'forward',
|
|
326
|
-
target: { host: '192.168.5.247', port: 443 }
|
|
327
|
-
}
|
|
328
|
-
}]
|
|
329
|
-
});
|
|
330
|
-
```
|
|
238
|
+
// Get metrics instance
|
|
239
|
+
const metrics = proxy.getMetrics();
|
|
331
240
|
|
|
332
|
-
|
|
241
|
+
// Connection metrics
|
|
242
|
+
console.log(`Active connections: ${metrics.connections.active()}`);
|
|
243
|
+
console.log(`Total connections: ${metrics.connections.total()}`);
|
|
333
244
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
- Trusted IP validation
|
|
338
|
-
- Connection record updates
|
|
245
|
+
// Throughput metrics
|
|
246
|
+
const instant = metrics.throughput.instant();
|
|
247
|
+
console.log(`Current: ${instant.in} bytes/sec in, ${instant.out} bytes/sec out`);
|
|
339
248
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
- Proxy chain with PROXY protocol
|
|
343
|
-
- Security: reject from untrusted IPs
|
|
344
|
-
- Performance: minimal overhead
|
|
345
|
-
- Compatibility: works with TLS passthrough
|
|
249
|
+
const recent = metrics.throughput.recent(); // Last 10 seconds
|
|
250
|
+
const average = metrics.throughput.average(); // Last 60 seconds
|
|
346
251
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
2. **Security test**: Ensure PROXY protocol rejected from untrusted sources
|
|
350
|
-
3. **Compatibility test**: Verify no impact on non-PROXY connections
|
|
351
|
-
4. **Performance test**: Measure overhead of PROXY protocol parsing
|
|
252
|
+
// Custom time window
|
|
253
|
+
const custom = metrics.throughput.custom(30); // Last 30 seconds
|
|
352
254
|
|
|
353
|
-
|
|
255
|
+
// Historical data for graphing
|
|
256
|
+
const history = metrics.throughput.history(300); // Last 5 minutes
|
|
257
|
+
history.forEach(point => {
|
|
258
|
+
console.log(`${new Date(point.timestamp)}: ${point.in} bytes/sec in, ${point.out} bytes/sec out`);
|
|
259
|
+
});
|
|
354
260
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
261
|
+
// Top routes by throughput
|
|
262
|
+
const routeThroughput = metrics.throughput.byRoute(60);
|
|
263
|
+
routeThroughput.forEach((stats, route) => {
|
|
264
|
+
console.log(`Route ${route}: ${stats.in} bytes/sec in, ${stats.out} bytes/sec out`);
|
|
265
|
+
});
|
|
359
266
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
- Rate limit connection attempts
|
|
267
|
+
// Request metrics
|
|
268
|
+
console.log(`RPS: ${metrics.requests.perSecond()}`);
|
|
269
|
+
console.log(`RPM: ${metrics.requests.perMinute()}`);
|
|
364
270
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
271
|
+
// Totals
|
|
272
|
+
console.log(`Total bytes in: ${metrics.totals.bytesIn()}`);
|
|
273
|
+
console.log(`Total bytes out: ${metrics.totals.bytesOut()}`);
|
|
274
|
+
```
|
|
368
275
|
|
|
369
|
-
|
|
276
|
+
## 7. Prometheus Export Example
|
|
370
277
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
278
|
+
```
|
|
279
|
+
# HELP smartproxy_throughput_bytes_per_second Current throughput in bytes per second
|
|
280
|
+
# TYPE smartproxy_throughput_bytes_per_second gauge
|
|
281
|
+
smartproxy_throughput_bytes_per_second{direction="in",window="1s"} 1234567
|
|
282
|
+
smartproxy_throughput_bytes_per_second{direction="out",window="1s"} 987654
|
|
283
|
+
smartproxy_throughput_bytes_per_second{direction="in",window="10s"} 1134567
|
|
284
|
+
smartproxy_throughput_bytes_per_second{direction="out",window="10s"} 887654
|
|
285
|
+
|
|
286
|
+
# HELP smartproxy_bytes_total Total bytes transferred
|
|
287
|
+
# TYPE smartproxy_bytes_total counter
|
|
288
|
+
smartproxy_bytes_total{direction="in"} 123456789
|
|
289
|
+
smartproxy_bytes_total{direction="out"} 98765432
|
|
290
|
+
|
|
291
|
+
# HELP smartproxy_active_connections Current number of active connections
|
|
292
|
+
# TYPE smartproxy_active_connections gauge
|
|
293
|
+
smartproxy_active_connections 42
|
|
294
|
+
|
|
295
|
+
# HELP smartproxy_connection_duration_seconds Connection duration in seconds
|
|
296
|
+
# TYPE smartproxy_connection_duration_seconds histogram
|
|
297
|
+
smartproxy_connection_duration_seconds_bucket{le="0.1"} 100
|
|
298
|
+
smartproxy_connection_duration_seconds_bucket{le="1"} 500
|
|
299
|
+
smartproxy_connection_duration_seconds_bucket{le="10"} 800
|
|
300
|
+
smartproxy_connection_duration_seconds_bucket{le="+Inf"} 850
|
|
301
|
+
smartproxy_connection_duration_seconds_sum 4250
|
|
302
|
+
smartproxy_connection_duration_seconds_count 850
|
|
303
|
+
```
|
|
375
304
|
|
|
376
|
-
|
|
305
|
+
## 8. Migration Strategy
|
|
377
306
|
|
|
378
|
-
|
|
379
|
-
-
|
|
380
|
-
-
|
|
381
|
-
-
|
|
307
|
+
### Breaking Changes
|
|
308
|
+
- Completely replace the old metrics API with the new clean design
|
|
309
|
+
- Remove all `get*` prefixed methods in favor of grouped properties
|
|
310
|
+
- Use simple `{ in, out }` objects instead of verbose property names
|
|
311
|
+
- Provide clear migration guide in documentation
|
|
382
312
|
|
|
383
|
-
###
|
|
313
|
+
### Implementation Approach
|
|
314
|
+
1. ✅ Create new `ThroughputTracker` class for time-series data
|
|
315
|
+
2. ✅ Implement new `IMetrics` interface with clean API
|
|
316
|
+
3. ✅ Replace `MetricsCollector` implementation entirely
|
|
317
|
+
4. ✅ Update all references to use new API
|
|
318
|
+
5. ⚠️ Add comprehensive tests for accuracy validation (partial)
|
|
384
319
|
|
|
385
|
-
|
|
386
|
-
-
|
|
387
|
-
-
|
|
388
|
-
-
|
|
320
|
+
### Additional Refactoring Completed
|
|
321
|
+
- Refactored all SmartProxy components to use cleaner dependency pattern
|
|
322
|
+
- Components now receive only `SmartProxy` instance instead of individual dependencies
|
|
323
|
+
- Access to other components via `this.smartProxy.componentName`
|
|
324
|
+
- Significantly simplified constructor signatures across the codebase
|
|
389
325
|
|
|
390
|
-
##
|
|
326
|
+
## 9. Success Metrics
|
|
391
327
|
|
|
392
|
-
|
|
393
|
-
|
|
328
|
+
- **Accuracy**: Throughput metrics accurate within 1% of actual
|
|
329
|
+
- **Performance**: < 1% CPU overhead for metrics collection
|
|
330
|
+
- **Memory**: < 10MB memory usage for 1 hour of data
|
|
331
|
+
- **Latency**: < 1ms to retrieve any metric
|
|
332
|
+
- **Reliability**: No metrics data loss under load
|
|
394
333
|
|
|
395
|
-
|
|
334
|
+
## 10. Future Enhancements
|
|
396
335
|
|
|
397
|
-
|
|
398
|
-
-
|
|
399
|
-
-
|
|
400
|
-
-
|
|
401
|
-
-
|
|
336
|
+
### Phase 5: Advanced Analytics
|
|
337
|
+
- Anomaly detection for traffic patterns
|
|
338
|
+
- Predictive analytics for capacity planning
|
|
339
|
+
- Correlation analysis between routes
|
|
340
|
+
- Real-time alerting integration
|
|
402
341
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
5. **Simplified Testing** - Easier to mock and test socket behavior
|
|
342
|
+
### Phase 6: Distributed Metrics
|
|
343
|
+
- Metrics aggregation across multiple proxies
|
|
344
|
+
- Distributed time-series storage
|
|
345
|
+
- Cross-proxy analytics
|
|
346
|
+
- Global dashboard support
|
|
409
347
|
|
|
410
|
-
|
|
348
|
+
## 11. Risks and Mitigations
|
|
411
349
|
|
|
412
|
-
|
|
413
|
-
|
|
350
|
+
### Risk: Memory Usage
|
|
351
|
+
- **Mitigation**: Circular buffers and configurable retention
|
|
352
|
+
- **Monitoring**: Track memory usage per metric type
|
|
414
353
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
public socket: net.Socket,
|
|
419
|
-
public realClientIP?: string,
|
|
420
|
-
public realClientPort?: number
|
|
421
|
-
) {}
|
|
422
|
-
|
|
423
|
-
get remoteAddress(): string {
|
|
424
|
-
return this.realClientIP || this.socket.remoteAddress || '';
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
get remotePort(): number {
|
|
428
|
-
return this.realClientPort || this.socket.remotePort || 0;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
get isFromTrustedProxy(): boolean {
|
|
432
|
-
return !!this.realClientIP;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
Integration points:
|
|
438
|
-
- Use in `RouteConnectionHandler` when receiving from trusted proxy IPs
|
|
439
|
-
- Update `ConnectionManager` to accept wrapped sockets
|
|
440
|
-
- Modify security checks to use `socket.remoteAddress` getter
|
|
441
|
-
|
|
442
|
-
#### Phase 2: Connection-Aware WrappedSocket (Alternative Design)
|
|
443
|
-
A more comprehensive design that manages both sides of a connection:
|
|
354
|
+
### Risk: Performance Impact
|
|
355
|
+
- **Mitigation**: Efficient data structures and caching
|
|
356
|
+
- **Testing**: Load test with metrics enabled/disabled
|
|
444
357
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
private socket: net.Socket;
|
|
449
|
-
private connectionId: string;
|
|
450
|
-
private metadata: ISocketMetadata;
|
|
451
|
-
|
|
452
|
-
constructor(socket: net.Socket, metadata?: Partial<ISocketMetadata>) {
|
|
453
|
-
super();
|
|
454
|
-
this.socket = socket;
|
|
455
|
-
this.connectionId = this.generateId();
|
|
456
|
-
this.metadata = { ...defaultMetadata, ...metadata };
|
|
457
|
-
this.setupHandlers();
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// ... single socket management
|
|
461
|
-
}
|
|
358
|
+
### Risk: Data Accuracy
|
|
359
|
+
- **Mitigation**: Atomic operations and proper synchronization
|
|
360
|
+
- **Validation**: Compare with external monitoring tools
|
|
462
361
|
|
|
463
|
-
|
|
464
|
-
class WrappedConnection extends EventEmitter {
|
|
465
|
-
private connectionId: string;
|
|
466
|
-
private incoming: WrappedSocket;
|
|
467
|
-
private outgoing?: WrappedSocket;
|
|
468
|
-
private forwardingActive: boolean = false;
|
|
469
|
-
|
|
470
|
-
constructor(incomingSocket: net.Socket) {
|
|
471
|
-
super();
|
|
472
|
-
this.connectionId = this.generateId();
|
|
473
|
-
this.incoming = new WrappedSocket(incomingSocket);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Connect to backend and set up forwarding
|
|
477
|
-
async connectToBackend(target: ITarget): Promise<void> {
|
|
478
|
-
const outgoingSocket = await this.createOutgoingConnection(target);
|
|
479
|
-
this.outgoing = new WrappedSocket(outgoingSocket);
|
|
480
|
-
await this.setupBidirectionalForwarding();
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
// Built-in forwarding logic from socket-utils
|
|
484
|
-
private async setupBidirectionalForwarding(): Promise<void> {
|
|
485
|
-
if (!this.outgoing) throw new Error('No outgoing socket');
|
|
486
|
-
|
|
487
|
-
// Handle data forwarding with backpressure
|
|
488
|
-
this.incoming.on('data', (chunk) => {
|
|
489
|
-
this.outgoing!.write(chunk, () => {
|
|
490
|
-
// Handle backpressure
|
|
491
|
-
});
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
this.outgoing.on('data', (chunk) => {
|
|
495
|
-
this.incoming.write(chunk, () => {
|
|
496
|
-
// Handle backpressure
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
// Handle connection lifecycle
|
|
501
|
-
const cleanup = (reason: string) => {
|
|
502
|
-
this.forwardingActive = false;
|
|
503
|
-
this.incoming.destroy();
|
|
504
|
-
this.outgoing?.destroy();
|
|
505
|
-
this.emit('closed', reason);
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
this.incoming.once('close', () => cleanup('incoming_closed'));
|
|
509
|
-
this.outgoing.once('close', () => cleanup('outgoing_closed'));
|
|
510
|
-
|
|
511
|
-
this.forwardingActive = true;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// PROXY protocol support
|
|
515
|
-
async handleProxyProtocol(trustedProxies: string[]): Promise<boolean> {
|
|
516
|
-
if (trustedProxies.includes(this.incoming.socket.remoteAddress)) {
|
|
517
|
-
const parsed = await this.incoming.parseProxyProtocol();
|
|
518
|
-
if (parsed && this.outgoing) {
|
|
519
|
-
// Forward PROXY protocol to backend if configured
|
|
520
|
-
await this.outgoing.sendProxyProtocol(this.incoming.realClientIP);
|
|
521
|
-
}
|
|
522
|
-
return parsed;
|
|
523
|
-
}
|
|
524
|
-
return false;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// Consolidated metrics
|
|
528
|
-
getMetrics(): IConnectionMetrics {
|
|
529
|
-
return {
|
|
530
|
-
connectionId: this.connectionId,
|
|
531
|
-
duration: Date.now() - this.startTime,
|
|
532
|
-
incoming: this.incoming.getMetrics(),
|
|
533
|
-
outgoing: this.outgoing?.getMetrics(),
|
|
534
|
-
totalBytes: this.getTotalBytes(),
|
|
535
|
-
state: this.getConnectionState()
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
#### Phase 3: Full Migration (Long-term)
|
|
542
|
-
- Replace all `net.Socket` usage with `WrappedSocket`
|
|
543
|
-
- Remove socket augmentation from `socket-augmentation.ts`
|
|
544
|
-
- Update all socket utilities to work with wrapped sockets
|
|
545
|
-
- Standardize socket handling across all components
|
|
546
|
-
|
|
547
|
-
### Integration with PROXY Protocol
|
|
548
|
-
|
|
549
|
-
The WrappedSocket class integrates seamlessly with PROXY protocol:
|
|
550
|
-
|
|
551
|
-
1. **Connection Acceptance**:
|
|
552
|
-
```typescript
|
|
553
|
-
const wrappedSocket = new ProxyProtocolSocket(socket);
|
|
554
|
-
if (this.isFromTrustedProxy(socket.remoteAddress)) {
|
|
555
|
-
await wrappedSocket.parseProxyProtocol(this.settings.proxyIPs);
|
|
556
|
-
}
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
2. **Security Checks**:
|
|
560
|
-
```typescript
|
|
561
|
-
// Automatically uses real client IP if available
|
|
562
|
-
const clientIP = wrappedSocket.remoteAddress;
|
|
563
|
-
if (!this.securityManager.isIPAllowed(clientIP)) {
|
|
564
|
-
wrappedSocket.destroy();
|
|
565
|
-
}
|
|
566
|
-
```
|
|
567
|
-
|
|
568
|
-
3. **Connection Records**:
|
|
569
|
-
```typescript
|
|
570
|
-
const record = this.connectionManager.createConnection(wrappedSocket);
|
|
571
|
-
// ConnectionManager uses wrappedSocket.remoteAddress transparently
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
### Option B Example: How It Would Replace Current Architecture
|
|
575
|
-
|
|
576
|
-
Instead of current approach with separate components:
|
|
577
|
-
```typescript
|
|
578
|
-
// Current: Multiple separate components
|
|
579
|
-
const record = connectionManager.createConnection(socket);
|
|
580
|
-
const { cleanupClient, cleanupServer } = createIndependentSocketHandlers(
|
|
581
|
-
clientSocket, serverSocket, onBothClosed
|
|
582
|
-
);
|
|
583
|
-
setupBidirectionalForwarding(clientSocket, serverSocket, handlers);
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
Option B would consolidate everything:
|
|
587
|
-
```typescript
|
|
588
|
-
// Option B: Single connection object
|
|
589
|
-
const connection = new WrappedConnection(incomingSocket);
|
|
590
|
-
await connection.handleProxyProtocol(trustedProxies);
|
|
591
|
-
await connection.connectToBackend({ host: 'server', port: 443 });
|
|
592
|
-
// Everything is handled internally - forwarding, cleanup, metrics
|
|
593
|
-
|
|
594
|
-
connection.on('closed', (reason) => {
|
|
595
|
-
logger.log('Connection closed', connection.getMetrics());
|
|
596
|
-
});
|
|
597
|
-
```
|
|
362
|
+
## Conclusion
|
|
598
363
|
|
|
599
|
-
This
|
|
600
|
-
- `IConnectionRecord` - absorbed into WrappedConnection
|
|
601
|
-
- `socket-utils.ts` functions - methods on WrappedConnection
|
|
602
|
-
- Separate incoming/outgoing tracking - unified in one object
|
|
603
|
-
- Manual cleanup coordination - automatic lifecycle management
|
|
604
|
-
|
|
605
|
-
Additional benefits with Option B:
|
|
606
|
-
- **Connection Pooling Integration**: WrappedConnection could integrate with EnhancedConnectionPool for backend connections
|
|
607
|
-
- **Unified Metrics**: Single point for all connection statistics
|
|
608
|
-
- **Protocol Negotiation**: Handle PROXY, TLS, HTTP/2 upgrade in one place
|
|
609
|
-
- **Resource Management**: Automatic cleanup with LifecycleComponent pattern
|
|
610
|
-
|
|
611
|
-
### Migration Path
|
|
612
|
-
|
|
613
|
-
1. **Week 1-2**: Implement minimal ProxyProtocolSocket (Option A)
|
|
614
|
-
2. **Week 3-4**: Test with PROXY protocol implementation
|
|
615
|
-
3. **Month 2**: Prototype WrappedConnection (Option B) if beneficial
|
|
616
|
-
4. **Month 3-6**: Gradual migration if Option B proves valuable
|
|
617
|
-
5. **Future**: Complete adoption in next major version
|
|
618
|
-
|
|
619
|
-
### Success Criteria
|
|
620
|
-
|
|
621
|
-
- PROXY protocol works transparently with wrapped sockets
|
|
622
|
-
- No performance regression (<0.1% overhead)
|
|
623
|
-
- Simplified code in connection handlers
|
|
624
|
-
- Better TypeScript type safety
|
|
625
|
-
- Easier to add new socket-level features
|
|
364
|
+
This plan transforms SmartProxy's metrics from a basic cumulative system to a comprehensive, time-series based monitoring solution suitable for production environments. The phased approach ensures minimal disruption while delivering immediate value through accurate throughput measurements.
|