@push.rocks/smartproxy 19.6.6 → 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 +1 -1
- package/readme.hints.md +0 -0
- package/readme.md +239 -73
- package/readme.plan.md +364 -0
- 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
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Manages timeouts and inactivity tracking for connections
|
|
3
3
|
*/
|
|
4
4
|
export class TimeoutManager {
|
|
5
|
-
constructor(
|
|
6
|
-
this.
|
|
5
|
+
constructor(smartProxy) {
|
|
6
|
+
this.smartProxy = smartProxy;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Ensure timeout values don't exceed Node.js max safe integer
|
|
@@ -34,14 +34,14 @@ export class TimeoutManager {
|
|
|
34
34
|
* Calculate effective inactivity timeout based on connection type
|
|
35
35
|
*/
|
|
36
36
|
getEffectiveInactivityTimeout(record) {
|
|
37
|
-
let effectiveTimeout = this.settings.inactivityTimeout || 14400000; // 4 hours default
|
|
37
|
+
let effectiveTimeout = this.smartProxy.settings.inactivityTimeout || 14400000; // 4 hours default
|
|
38
38
|
// For immortal keep-alive connections, use an extremely long timeout
|
|
39
|
-
if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
|
|
39
|
+
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
40
40
|
return Number.MAX_SAFE_INTEGER;
|
|
41
41
|
}
|
|
42
42
|
// For extended keep-alive connections, apply multiplier
|
|
43
|
-
if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'extended') {
|
|
44
|
-
const multiplier = this.settings.keepAliveInactivityMultiplier || 6;
|
|
43
|
+
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'extended') {
|
|
44
|
+
const multiplier = this.smartProxy.settings.keepAliveInactivityMultiplier || 6;
|
|
45
45
|
effectiveTimeout = effectiveTimeout * multiplier;
|
|
46
46
|
}
|
|
47
47
|
return this.ensureSafeTimeout(effectiveTimeout);
|
|
@@ -52,19 +52,19 @@ export class TimeoutManager {
|
|
|
52
52
|
getEffectiveMaxLifetime(record) {
|
|
53
53
|
// Use route-specific timeout if available from the routeConfig
|
|
54
54
|
const baseTimeout = record.routeConfig?.action.advanced?.timeout ||
|
|
55
|
-
this.settings.maxConnectionLifetime ||
|
|
55
|
+
this.smartProxy.settings.maxConnectionLifetime ||
|
|
56
56
|
86400000; // 24 hours default
|
|
57
57
|
// For immortal keep-alive connections, use an extremely long lifetime
|
|
58
|
-
if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
|
|
58
|
+
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
59
59
|
return Number.MAX_SAFE_INTEGER;
|
|
60
60
|
}
|
|
61
61
|
// For extended keep-alive connections, use the extended lifetime setting
|
|
62
|
-
if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'extended') {
|
|
63
|
-
return this.ensureSafeTimeout(this.settings.extendedKeepAliveLifetime || 7 * 24 * 60 * 60 * 1000 // 7 days default
|
|
62
|
+
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'extended') {
|
|
63
|
+
return this.ensureSafeTimeout(this.smartProxy.settings.extendedKeepAliveLifetime || 7 * 24 * 60 * 60 * 1000 // 7 days default
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
66
|
// Apply randomization if enabled
|
|
67
|
-
if (this.settings.enableRandomizedTimeouts) {
|
|
67
|
+
if (this.smartProxy.settings.enableRandomizedTimeouts) {
|
|
68
68
|
return this.randomizeTimeout(baseTimeout);
|
|
69
69
|
}
|
|
70
70
|
return this.ensureSafeTimeout(baseTimeout);
|
|
@@ -97,7 +97,7 @@ export class TimeoutManager {
|
|
|
97
97
|
*/
|
|
98
98
|
checkInactivity(record) {
|
|
99
99
|
// Skip for connections with inactivity check disabled
|
|
100
|
-
if (this.settings.disableInactivityCheck) {
|
|
100
|
+
if (this.smartProxy.settings.disableInactivityCheck) {
|
|
101
101
|
return {
|
|
102
102
|
isInactive: false,
|
|
103
103
|
shouldWarn: false,
|
|
@@ -106,7 +106,7 @@ export class TimeoutManager {
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
// Skip for immortal keep-alive connections
|
|
109
|
-
if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
|
|
109
|
+
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
110
110
|
return {
|
|
111
111
|
isInactive: false,
|
|
112
112
|
shouldWarn: false,
|
|
@@ -135,7 +135,7 @@ export class TimeoutManager {
|
|
|
135
135
|
*/
|
|
136
136
|
applySocketTimeouts(record) {
|
|
137
137
|
// Skip for immortal keep-alive connections
|
|
138
|
-
if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
|
|
138
|
+
if (record.hasKeepAlive && this.smartProxy.settings.keepAliveTreatment === 'immortal') {
|
|
139
139
|
// Disable timeouts completely for immortal connections
|
|
140
140
|
record.incoming.setTimeout(0);
|
|
141
141
|
if (record.outgoing) {
|
|
@@ -144,11 +144,11 @@ export class TimeoutManager {
|
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
146
146
|
// Apply normal timeouts
|
|
147
|
-
const timeout = this.ensureSafeTimeout(this.settings.socketTimeout || 3600000); // 1 hour default
|
|
147
|
+
const timeout = this.ensureSafeTimeout(this.smartProxy.settings.socketTimeout || 3600000); // 1 hour default
|
|
148
148
|
record.incoming.setTimeout(timeout);
|
|
149
149
|
if (record.outgoing) {
|
|
150
150
|
record.outgoing.setTimeout(timeout);
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
154
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZW91dC1tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvcHJveGllcy9zbWFydC1wcm94eS90aW1lb3V0LW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0E7O0dBRUc7QUFDSCxNQUFNLE9BQU8sY0FBYztJQUN6QixZQUFvQixVQUFzQjtRQUF0QixlQUFVLEdBQVYsVUFBVSxDQUFZO0lBQUcsQ0FBQztJQUU5Qzs7T0FFRztJQUNJLGlCQUFpQixDQUFDLE9BQWU7UUFDdEMsTUFBTSxnQkFBZ0IsR0FBRyxVQUFVLENBQUMsQ0FBQyxnQ0FBZ0M7UUFDckUsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxnQkFBZ0IsQ0FBQyxXQUFtQixFQUFFLG1CQUEyQixDQUFDO1FBQ3ZFLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM1RCxNQUFNLFNBQVMsR0FBRyxlQUFlLEdBQUcsQ0FBQyxnQkFBZ0IsR0FBRyxHQUFHLENBQUMsQ0FBQztRQUM3RCxPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FDM0IsZUFBZSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLFNBQVMsR0FBRyxDQUFDLENBQUMsR0FBRyxTQUFTLENBQ3hFLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSxjQUFjLENBQUMsTUFBeUI7UUFDN0MsTUFBTSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFakMsK0JBQStCO1FBQy9CLElBQUksTUFBTSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDbkMsTUFBTSxDQUFDLHVCQUF1QixHQUFHLEtBQUssQ0FBQztRQUN6QyxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksNkJBQTZCLENBQUMsTUFBeUI7UUFDNUQsSUFBSSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsSUFBSSxRQUFRLENBQUMsQ0FBQyxrQkFBa0I7UUFFakcscUVBQXFFO1FBQ3JFLElBQUksTUFBTSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUN0RixPQUFPLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztRQUNqQyxDQUFDO1FBRUQsd0RBQXdEO1FBQ3hELElBQUksTUFBTSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUN0RixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLENBQUM7WUFDL0UsZ0JBQWdCLEdBQUcsZ0JBQWdCLEdBQUcsVUFBVSxDQUFDO1FBQ25ELENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRDs7T0FFRztJQUNJLHVCQUF1QixDQUFDLE1BQXlCO1FBQ3RELCtEQUErRDtRQUMvRCxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsT0FBTztZQUM1QyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUI7WUFDOUMsUUFBUSxDQUFDLENBQUMsbUJBQW1CO1FBRWpELHNFQUFzRTtRQUN0RSxJQUFJLE1BQU0sQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsa0JBQWtCLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDdEYsT0FBTyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7UUFDakMsQ0FBQztRQUVELHlFQUF5RTtRQUN6RSxJQUFJLE1BQU0sQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsa0JBQWtCLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDdEYsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQzNCLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLHlCQUF5QixJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsaUJBQWlCO2FBQ2hHLENBQUM7UUFDSixDQUFDO1FBRUQsaUNBQWlDO1FBQ2pDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztZQUN0RCxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM1QyxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVEOzs7T0FHRztJQUNJLHNCQUFzQixDQUMzQixNQUF5QixFQUN6QixTQUE4RDtRQUU5RCwyQkFBMkI7UUFDM0IsSUFBSSxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDeEIsWUFBWSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNwQyxDQUFDO1FBRUQsOEJBQThCO1FBQzlCLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRS9ELHFCQUFxQjtRQUNyQixNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQzVCLDZCQUE2QjtZQUM3QixTQUFTLENBQUMsTUFBTSxFQUFFLG9CQUFvQixDQUFDLENBQUM7UUFDMUMsQ0FBQyxFQUFFLGlCQUFpQixDQUFDLENBQUM7UUFFdEIsbURBQW1EO1FBQ25ELElBQUksS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2hCLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNoQixDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksZUFBZSxDQUFDLE1BQXlCO1FBTTlDLHNEQUFzRDtRQUN0RCxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLHNCQUFzQixFQUFFLENBQUM7WUFDcEQsT0FBTztnQkFDTCxVQUFVLEVBQUUsS0FBSztnQkFDakIsVUFBVSxFQUFFLEtBQUs7Z0JBQ2pCLGNBQWMsRUFBRSxDQUFDO2dCQUNqQixnQkFBZ0IsRUFBRSxDQUFDO2FBQ3BCLENBQUM7UUFDSixDQUFDO1FBRUQsMkNBQTJDO1FBQzNDLElBQUksTUFBTSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUN0RixPQUFPO2dCQUNMLFVBQVUsRUFBRSxLQUFLO2dCQUNqQixVQUFVLEVBQUUsS0FBSztnQkFDakIsY0FBYyxFQUFFLENBQUM7Z0JBQ2pCLGdCQUFnQixFQUFFLENBQUM7YUFDcEIsQ0FBQztRQUNKLENBQUM7UUFFRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDdkIsTUFBTSxjQUFjLEdBQUcsR0FBRyxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUM7UUFDakQsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsNkJBQTZCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFcEUsb0JBQW9CO1FBQ3BCLE1BQU0sVUFBVSxHQUFHLGNBQWMsR0FBRyxnQkFBZ0IsQ0FBQztRQUVyRCxtREFBbUQ7UUFDbkQsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFlBQVk7WUFDbkIsVUFBVTtZQUNWLENBQUMsTUFBTSxDQUFDLHVCQUF1QixDQUFDO1FBRW5ELE9BQU87WUFDTCxVQUFVO1lBQ1YsVUFBVTtZQUNWLGNBQWM7WUFDZCxnQkFBZ0I7U0FDakIsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNJLG1CQUFtQixDQUFDLE1BQXlCO1FBQ2xELDJDQUEyQztRQUMzQyxJQUFJLE1BQU0sQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsa0JBQWtCLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDdEYsdURBQXVEO1lBQ3ZELE1BQU0sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzlCLElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUNwQixNQUFNLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNoQyxDQUFDO1lBQ0QsT0FBTztRQUNULENBQUM7UUFFRCx3QkFBd0I7UUFDeEIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLGFBQWEsSUFBSSxPQUFPLENBQUMsQ0FBQyxDQUFDLGlCQUFpQjtRQUM1RyxNQUFNLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNwQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNwQixNQUFNLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0QyxDQUFDO0lBQ0gsQ0FBQztDQUNGIn0=
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SmartProxy } from './smart-proxy.js';
|
|
2
2
|
/**
|
|
3
3
|
* Interface for connection information used for SNI extraction
|
|
4
4
|
*/
|
|
@@ -12,8 +12,8 @@ interface IConnectionInfo {
|
|
|
12
12
|
* Manages TLS-related operations including SNI extraction and validation
|
|
13
13
|
*/
|
|
14
14
|
export declare class TlsManager {
|
|
15
|
-
private
|
|
16
|
-
constructor(
|
|
15
|
+
private smartProxy;
|
|
16
|
+
constructor(smartProxy: SmartProxy);
|
|
17
17
|
/**
|
|
18
18
|
* Check if a data chunk appears to be a TLS handshake
|
|
19
19
|
*/
|
|
@@ -4,8 +4,8 @@ import { SniHandler } from '../../tls/sni/sni-handler.js';
|
|
|
4
4
|
* Manages TLS-related operations including SNI extraction and validation
|
|
5
5
|
*/
|
|
6
6
|
export class TlsManager {
|
|
7
|
-
constructor(
|
|
8
|
-
this.
|
|
7
|
+
constructor(smartProxy) {
|
|
8
|
+
this.smartProxy = smartProxy;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* Check if a data chunk appears to be a TLS handshake
|
|
@@ -24,21 +24,21 @@ export class TlsManager {
|
|
|
24
24
|
*/
|
|
25
25
|
extractSNI(chunk, connInfo, previousDomain) {
|
|
26
26
|
// Use the SniHandler to process the TLS packet
|
|
27
|
-
return SniHandler.processTlsPacket(chunk, connInfo, this.settings.enableTlsDebugLogging || false, previousDomain);
|
|
27
|
+
return SniHandler.processTlsPacket(chunk, connInfo, this.smartProxy.settings.enableTlsDebugLogging || false, previousDomain);
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Handle session resumption attempts
|
|
31
31
|
*/
|
|
32
32
|
handleSessionResumption(chunk, connectionId, hasSNI) {
|
|
33
33
|
// Skip if session tickets are allowed
|
|
34
|
-
if (this.settings.allowSessionTicket !== false) {
|
|
34
|
+
if (this.smartProxy.settings.allowSessionTicket !== false) {
|
|
35
35
|
return { shouldBlock: false };
|
|
36
36
|
}
|
|
37
37
|
// Check for session resumption attempt
|
|
38
|
-
const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.settings.enableTlsDebugLogging || false);
|
|
38
|
+
const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.smartProxy.settings.enableTlsDebugLogging || false);
|
|
39
39
|
// If this is a resumption attempt without SNI, block it
|
|
40
40
|
if (resumptionInfo.isResumption && !hasSNI && !resumptionInfo.hasSNI) {
|
|
41
|
-
if (this.settings.enableTlsDebugLogging) {
|
|
41
|
+
if (this.smartProxy.settings.enableTlsDebugLogging) {
|
|
42
42
|
console.log(`[${connectionId}] Session resumption detected without SNI and allowSessionTicket=false. ` +
|
|
43
43
|
`Terminating connection to force new TLS handshake.`);
|
|
44
44
|
}
|
|
@@ -59,19 +59,19 @@ export class TlsManager {
|
|
|
59
59
|
}
|
|
60
60
|
try {
|
|
61
61
|
// Extract SNI with renegotiation support
|
|
62
|
-
const newSNI = SniHandler.extractSNIWithResumptionSupport(chunk, connInfo, this.settings.enableTlsDebugLogging || false);
|
|
62
|
+
const newSNI = SniHandler.extractSNIWithResumptionSupport(chunk, connInfo, this.smartProxy.settings.enableTlsDebugLogging || false);
|
|
63
63
|
// Skip if no SNI was found
|
|
64
64
|
if (!newSNI)
|
|
65
65
|
return { hasMismatch: false };
|
|
66
66
|
// Check for SNI mismatch
|
|
67
67
|
if (newSNI !== expectedDomain) {
|
|
68
|
-
if (this.settings.enableTlsDebugLogging) {
|
|
68
|
+
if (this.smartProxy.settings.enableTlsDebugLogging) {
|
|
69
69
|
console.log(`[${connectionId}] Renegotiation with different SNI: ${expectedDomain} -> ${newSNI}. ` +
|
|
70
70
|
`Terminating connection - SNI domain switching is not allowed.`);
|
|
71
71
|
}
|
|
72
72
|
return { hasMismatch: true, extractedSNI: newSNI };
|
|
73
73
|
}
|
|
74
|
-
else if (this.settings.enableTlsDebugLogging) {
|
|
74
|
+
else if (this.smartProxy.settings.enableTlsDebugLogging) {
|
|
75
75
|
console.log(`[${connectionId}] Renegotiation detected with same SNI: ${newSNI}. Allowing.`);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -108,9 +108,9 @@ export class TlsManager {
|
|
|
108
108
|
return result;
|
|
109
109
|
}
|
|
110
110
|
// Check for session resumption
|
|
111
|
-
const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.settings.enableTlsDebugLogging || false);
|
|
111
|
+
const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.smartProxy.settings.enableTlsDebugLogging || false);
|
|
112
112
|
// Extract SNI
|
|
113
|
-
const sni = SniHandler.extractSNI(chunk, this.settings.enableTlsDebugLogging || false);
|
|
113
|
+
const sni = SniHandler.extractSNI(chunk, this.smartProxy.settings.enableTlsDebugLogging || false);
|
|
114
114
|
// Update result
|
|
115
115
|
result.isRenewal = resumptionInfo.isResumption;
|
|
116
116
|
result.hasSNI = !!sni;
|
|
@@ -129,4 +129,4 @@ export class TlsManager {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
132
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGxzLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3Rscy1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBYTFEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFVBQVU7SUFDckIsWUFBb0IsVUFBc0I7UUFBdEIsZUFBVSxHQUFWLFVBQVUsQ0FBWTtJQUFHLENBQUM7SUFFOUM7O09BRUc7SUFDSSxjQUFjLENBQUMsS0FBYTtRQUNqQyxPQUFPLFVBQVUsQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDMUMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksYUFBYSxDQUFDLEtBQWE7UUFDaEMsT0FBTyxVQUFVLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7T0FFRztJQUNJLFVBQVUsQ0FDZixLQUFhLEVBQ2IsUUFBeUIsRUFDekIsY0FBdUI7UUFFdkIsK0NBQStDO1FBQy9DLE9BQU8sVUFBVSxDQUFDLGdCQUFnQixDQUNoQyxLQUFLLEVBQ0wsUUFBUSxFQUNSLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLHFCQUFxQixJQUFJLEtBQUssRUFDdkQsY0FBYyxDQUNmLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSx1QkFBdUIsQ0FDNUIsS0FBYSxFQUNiLFlBQW9CLEVBQ3BCLE1BQWU7UUFFZixzQ0FBc0M7UUFDdEMsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUMxRCxPQUFPLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQ2hDLENBQUM7UUFFRCx1Q0FBdUM7UUFDdkMsTUFBTSxjQUFjLEdBQUcs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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartproxy",
|
|
3
|
-
"version": "19.6.
|
|
3
|
+
"version": "19.6.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
package/readme.hints.md
ADDED
|
File without changes
|
package/readme.md
CHANGED
|
@@ -1576,150 +1576,316 @@ Available helper functions:
|
|
|
1576
1576
|
|
|
1577
1577
|
## Metrics and Monitoring
|
|
1578
1578
|
|
|
1579
|
-
SmartProxy includes a comprehensive metrics collection system that provides real-time insights into proxy performance, connection statistics, and throughput data.
|
|
1579
|
+
SmartProxy includes a comprehensive metrics collection system that provides real-time insights into proxy performance, connection statistics, and throughput data. The metrics system uses a clean, grouped API design for intuitive access to different metric categories.
|
|
1580
1580
|
|
|
1581
|
-
###
|
|
1581
|
+
### Enabling Metrics
|
|
1582
1582
|
|
|
1583
1583
|
```typescript
|
|
1584
|
-
const proxy = new SmartProxy({
|
|
1584
|
+
const proxy = new SmartProxy({
|
|
1585
|
+
// Enable metrics collection
|
|
1586
|
+
metrics: {
|
|
1587
|
+
enabled: true,
|
|
1588
|
+
sampleIntervalMs: 1000, // Sample throughput every second
|
|
1589
|
+
retentionSeconds: 3600 // Keep 1 hour of history
|
|
1590
|
+
},
|
|
1591
|
+
routes: [/* your routes */]
|
|
1592
|
+
});
|
|
1593
|
+
|
|
1585
1594
|
await proxy.start();
|
|
1595
|
+
```
|
|
1586
1596
|
|
|
1587
|
-
|
|
1588
|
-
const stats = proxy.getStats();
|
|
1597
|
+
### Getting Metrics
|
|
1589
1598
|
|
|
1590
|
-
|
|
1591
|
-
|
|
1599
|
+
```typescript
|
|
1600
|
+
// Access metrics through the getMetrics() method
|
|
1601
|
+
const metrics = proxy.getMetrics();
|
|
1592
1602
|
|
|
1593
|
-
//
|
|
1594
|
-
|
|
1603
|
+
// The metrics object provides grouped methods for different categories
|
|
1604
|
+
```
|
|
1595
1605
|
|
|
1596
|
-
|
|
1597
|
-
console.log(`Current RPS: ${stats.getRequestsPerSecond()}`);
|
|
1606
|
+
### Connection Metrics
|
|
1598
1607
|
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1608
|
+
Monitor active connections, total connections, and connection distribution:
|
|
1609
|
+
|
|
1610
|
+
```typescript
|
|
1611
|
+
// Get current active connections
|
|
1612
|
+
console.log(`Active connections: ${metrics.connections.active()}`);
|
|
1613
|
+
|
|
1614
|
+
// Get total connections since start
|
|
1615
|
+
console.log(`Total connections: ${metrics.connections.total()}`);
|
|
1603
1616
|
|
|
1604
1617
|
// Get connections by route
|
|
1605
|
-
const routeConnections =
|
|
1618
|
+
const routeConnections = metrics.connections.byRoute();
|
|
1606
1619
|
for (const [route, count] of routeConnections) {
|
|
1607
1620
|
console.log(`Route ${route}: ${count} connections`);
|
|
1608
1621
|
}
|
|
1609
1622
|
|
|
1610
1623
|
// Get connections by IP address
|
|
1611
|
-
const ipConnections =
|
|
1624
|
+
const ipConnections = metrics.connections.byIP();
|
|
1612
1625
|
for (const [ip, count] of ipConnections) {
|
|
1613
1626
|
console.log(`IP ${ip}: ${count} connections`);
|
|
1614
1627
|
}
|
|
1628
|
+
|
|
1629
|
+
// Get top IPs by connection count
|
|
1630
|
+
const topIPs = metrics.connections.topIPs(10);
|
|
1631
|
+
topIPs.forEach(({ ip, count }) => {
|
|
1632
|
+
console.log(`${ip}: ${count} connections`);
|
|
1633
|
+
});
|
|
1615
1634
|
```
|
|
1616
1635
|
|
|
1617
|
-
###
|
|
1636
|
+
### Throughput Metrics
|
|
1618
1637
|
|
|
1619
|
-
|
|
1638
|
+
Real-time and historical throughput data with customizable time windows:
|
|
1620
1639
|
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1640
|
+
```typescript
|
|
1641
|
+
// Get instant throughput (last 1 second)
|
|
1642
|
+
const instant = metrics.throughput.instant();
|
|
1643
|
+
console.log(`Current: ${instant.in} bytes/sec in, ${instant.out} bytes/sec out`);
|
|
1644
|
+
|
|
1645
|
+
// Get recent throughput (last 10 seconds average)
|
|
1646
|
+
const recent = metrics.throughput.recent();
|
|
1647
|
+
console.log(`Recent: ${recent.in} bytes/sec in, ${recent.out} bytes/sec out`);
|
|
1648
|
+
|
|
1649
|
+
// Get average throughput (last 60 seconds)
|
|
1650
|
+
const average = metrics.throughput.average();
|
|
1651
|
+
console.log(`Average: ${average.in} bytes/sec in, ${average.out} bytes/sec out`);
|
|
1652
|
+
|
|
1653
|
+
// Get custom time window (e.g., last 5 minutes)
|
|
1654
|
+
const custom = metrics.throughput.custom(300);
|
|
1655
|
+
console.log(`5-min avg: ${custom.in} bytes/sec in, ${custom.out} bytes/sec out`);
|
|
1656
|
+
|
|
1657
|
+
// Get throughput history for graphing
|
|
1658
|
+
const history = metrics.throughput.history(300); // Last 5 minutes
|
|
1659
|
+
history.forEach(point => {
|
|
1660
|
+
console.log(`${new Date(point.timestamp)}: ${point.in} in, ${point.out} out`);
|
|
1661
|
+
});
|
|
1662
|
+
|
|
1663
|
+
// Get throughput by route
|
|
1664
|
+
const routeThroughput = metrics.throughput.byRoute(60); // Last 60 seconds
|
|
1665
|
+
routeThroughput.forEach((stats, route) => {
|
|
1666
|
+
console.log(`Route ${route}: ${stats.in} in, ${stats.out} out bytes/sec`);
|
|
1667
|
+
});
|
|
1627
1668
|
|
|
1628
|
-
|
|
1669
|
+
// Get throughput by IP
|
|
1670
|
+
const ipThroughput = metrics.throughput.byIP(60);
|
|
1671
|
+
ipThroughput.forEach((stats, ip) => {
|
|
1672
|
+
console.log(`IP ${ip}: ${stats.in} in, ${stats.out} out bytes/sec`);
|
|
1673
|
+
});
|
|
1674
|
+
```
|
|
1629
1675
|
|
|
1630
|
-
|
|
1631
|
-
- `getTopIPs(limit?: number)`: Get top IPs by connection count
|
|
1632
|
-
- `isIPBlocked(ip: string, maxConnectionsPerIP: number)`: Check if an IP has reached the connection limit
|
|
1676
|
+
### Request Metrics
|
|
1633
1677
|
|
|
1634
|
-
|
|
1678
|
+
Track request rates:
|
|
1635
1679
|
|
|
1636
1680
|
```typescript
|
|
1637
|
-
|
|
1681
|
+
// Get requests per second
|
|
1682
|
+
console.log(`RPS: ${metrics.requests.perSecond()}`);
|
|
1638
1683
|
|
|
1639
|
-
// Get
|
|
1640
|
-
|
|
1641
|
-
console.log(`Incoming: ${rate.bytesInPerSec} bytes/sec`);
|
|
1642
|
-
console.log(`Outgoing: ${rate.bytesOutPerSec} bytes/sec`);
|
|
1684
|
+
// Get requests per minute
|
|
1685
|
+
console.log(`RPM: ${metrics.requests.perMinute()}`);
|
|
1643
1686
|
|
|
1644
|
-
// Get
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
console.log(`${ip}: ${connections} connections`);
|
|
1648
|
-
});
|
|
1687
|
+
// Get total requests
|
|
1688
|
+
console.log(`Total requests: ${metrics.requests.total()}`);
|
|
1689
|
+
```
|
|
1649
1690
|
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1691
|
+
### Cumulative Totals
|
|
1692
|
+
|
|
1693
|
+
Track total bytes transferred and connections:
|
|
1694
|
+
|
|
1695
|
+
```typescript
|
|
1696
|
+
// Get total bytes
|
|
1697
|
+
console.log(`Total bytes in: ${metrics.totals.bytesIn()}`);
|
|
1698
|
+
console.log(`Total bytes out: ${metrics.totals.bytesOut()}`);
|
|
1699
|
+
console.log(`Total connections: ${metrics.totals.connections()}`);
|
|
1654
1700
|
```
|
|
1655
1701
|
|
|
1656
|
-
###
|
|
1702
|
+
### Performance Percentiles
|
|
1703
|
+
|
|
1704
|
+
Get percentile statistics (when implemented):
|
|
1657
1705
|
|
|
1658
1706
|
```typescript
|
|
1659
|
-
//
|
|
1707
|
+
// Connection duration percentiles
|
|
1708
|
+
const durations = metrics.percentiles.connectionDuration();
|
|
1709
|
+
console.log(`Connection durations - P50: ${durations.p50}ms, P95: ${durations.p95}ms, P99: ${durations.p99}ms`);
|
|
1710
|
+
|
|
1711
|
+
// Bytes transferred percentiles
|
|
1712
|
+
const bytes = metrics.percentiles.bytesTransferred();
|
|
1713
|
+
console.log(`Bytes in - P50: ${bytes.in.p50}, P95: ${bytes.in.p95}, P99: ${bytes.in.p99}`);
|
|
1714
|
+
console.log(`Bytes out - P50: ${bytes.out.p50}, P95: ${bytes.out.p95}, P99: ${bytes.out.p99}`);
|
|
1715
|
+
```
|
|
1716
|
+
|
|
1717
|
+
### Complete Monitoring Example
|
|
1718
|
+
|
|
1719
|
+
```typescript
|
|
1720
|
+
// Create a monitoring dashboard
|
|
1660
1721
|
setInterval(() => {
|
|
1661
|
-
const
|
|
1722
|
+
const metrics = proxy.getMetrics();
|
|
1662
1723
|
|
|
1663
1724
|
// Log key metrics
|
|
1664
1725
|
console.log({
|
|
1665
1726
|
timestamp: new Date().toISOString(),
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1727
|
+
connections: {
|
|
1728
|
+
active: metrics.connections.active(),
|
|
1729
|
+
total: metrics.connections.total()
|
|
1730
|
+
},
|
|
1731
|
+
throughput: {
|
|
1732
|
+
instant: metrics.throughput.instant(),
|
|
1733
|
+
average: metrics.throughput.average()
|
|
1734
|
+
},
|
|
1735
|
+
requests: {
|
|
1736
|
+
rps: metrics.requests.perSecond(),
|
|
1737
|
+
total: metrics.requests.total()
|
|
1738
|
+
},
|
|
1739
|
+
totals: {
|
|
1740
|
+
bytesIn: metrics.totals.bytesIn(),
|
|
1741
|
+
bytesOut: metrics.totals.bytesOut()
|
|
1742
|
+
}
|
|
1669
1743
|
});
|
|
1670
1744
|
|
|
1671
|
-
//
|
|
1672
|
-
const
|
|
1673
|
-
|
|
1745
|
+
// Alert on high connection counts
|
|
1746
|
+
const topIPs = metrics.connections.topIPs(5);
|
|
1747
|
+
topIPs.forEach(({ ip, count }) => {
|
|
1674
1748
|
if (count > 100) {
|
|
1675
1749
|
console.warn(`High connection count from ${ip}: ${count}`);
|
|
1676
1750
|
}
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
// Alert on high throughput
|
|
1754
|
+
const instant = metrics.throughput.instant();
|
|
1755
|
+
if (instant.in > 100_000_000) { // 100 MB/s
|
|
1756
|
+
console.warn(`High incoming throughput: ${instant.in} bytes/sec`);
|
|
1677
1757
|
}
|
|
1678
1758
|
}, 10000); // Every 10 seconds
|
|
1679
1759
|
```
|
|
1680
1760
|
|
|
1681
1761
|
### Exporting Metrics
|
|
1682
1762
|
|
|
1683
|
-
|
|
1763
|
+
Export metrics in various formats for external monitoring systems:
|
|
1684
1764
|
|
|
1685
1765
|
```typescript
|
|
1686
1766
|
// Export as JSON
|
|
1687
1767
|
app.get('/metrics.json', (req, res) => {
|
|
1688
|
-
const
|
|
1768
|
+
const metrics = proxy.getMetrics();
|
|
1689
1769
|
res.json({
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1770
|
+
connections: {
|
|
1771
|
+
active: metrics.connections.active(),
|
|
1772
|
+
total: metrics.connections.total(),
|
|
1773
|
+
byRoute: Object.fromEntries(metrics.connections.byRoute()),
|
|
1774
|
+
byIP: Object.fromEntries(metrics.connections.byIP())
|
|
1775
|
+
},
|
|
1776
|
+
throughput: {
|
|
1777
|
+
instant: metrics.throughput.instant(),
|
|
1778
|
+
recent: metrics.throughput.recent(),
|
|
1779
|
+
average: metrics.throughput.average()
|
|
1780
|
+
},
|
|
1781
|
+
requests: {
|
|
1782
|
+
perSecond: metrics.requests.perSecond(),
|
|
1783
|
+
perMinute: metrics.requests.perMinute(),
|
|
1784
|
+
total: metrics.requests.total()
|
|
1785
|
+
},
|
|
1786
|
+
totals: {
|
|
1787
|
+
bytesIn: metrics.totals.bytesIn(),
|
|
1788
|
+
bytesOut: metrics.totals.bytesOut(),
|
|
1789
|
+
connections: metrics.totals.connections()
|
|
1790
|
+
}
|
|
1696
1791
|
});
|
|
1697
1792
|
});
|
|
1698
1793
|
|
|
1699
1794
|
// Export as Prometheus format
|
|
1700
1795
|
app.get('/metrics', (req, res) => {
|
|
1701
|
-
const
|
|
1796
|
+
const metrics = proxy.getMetrics();
|
|
1797
|
+
const instant = metrics.throughput.instant();
|
|
1798
|
+
|
|
1702
1799
|
res.set('Content-Type', 'text/plain');
|
|
1703
1800
|
res.send(`
|
|
1704
|
-
# HELP
|
|
1705
|
-
# TYPE
|
|
1706
|
-
|
|
1801
|
+
# HELP smartproxy_connections_active Current active connections
|
|
1802
|
+
# TYPE smartproxy_connections_active gauge
|
|
1803
|
+
smartproxy_connections_active ${metrics.connections.active()}
|
|
1804
|
+
|
|
1805
|
+
# HELP smartproxy_connections_total Total connections since start
|
|
1806
|
+
# TYPE smartproxy_connections_total counter
|
|
1807
|
+
smartproxy_connections_total ${metrics.connections.total()}
|
|
1808
|
+
|
|
1809
|
+
# HELP smartproxy_throughput_bytes_per_second Current throughput in bytes per second
|
|
1810
|
+
# TYPE smartproxy_throughput_bytes_per_second gauge
|
|
1811
|
+
smartproxy_throughput_bytes_per_second{direction="in"} ${instant.in}
|
|
1812
|
+
smartproxy_throughput_bytes_per_second{direction="out"} ${instant.out}
|
|
1707
1813
|
|
|
1708
1814
|
# HELP smartproxy_requests_per_second Current requests per second
|
|
1709
1815
|
# TYPE smartproxy_requests_per_second gauge
|
|
1710
|
-
smartproxy_requests_per_second ${
|
|
1816
|
+
smartproxy_requests_per_second ${metrics.requests.perSecond()}
|
|
1711
1817
|
|
|
1712
|
-
# HELP
|
|
1713
|
-
# TYPE
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
# HELP smartproxy_bytes_out Total bytes sent
|
|
1717
|
-
# TYPE smartproxy_bytes_out counter
|
|
1718
|
-
smartproxy_bytes_out ${stats.getThroughput().bytesOut}
|
|
1818
|
+
# HELP smartproxy_bytes_total Total bytes transferred
|
|
1819
|
+
# TYPE smartproxy_bytes_total counter
|
|
1820
|
+
smartproxy_bytes_total{direction="in"} ${metrics.totals.bytesIn()}
|
|
1821
|
+
smartproxy_bytes_total{direction="out"} ${metrics.totals.bytesOut()}
|
|
1719
1822
|
`);
|
|
1720
1823
|
});
|
|
1721
1824
|
```
|
|
1722
1825
|
|
|
1826
|
+
### Metrics API Reference
|
|
1827
|
+
|
|
1828
|
+
The metrics API is organized into logical groups:
|
|
1829
|
+
|
|
1830
|
+
```typescript
|
|
1831
|
+
interface IMetrics {
|
|
1832
|
+
connections: {
|
|
1833
|
+
active(): number;
|
|
1834
|
+
total(): number;
|
|
1835
|
+
byRoute(): Map<string, number>;
|
|
1836
|
+
byIP(): Map<string, number>;
|
|
1837
|
+
topIPs(limit?: number): Array<{ ip: string; count: number }>;
|
|
1838
|
+
};
|
|
1839
|
+
|
|
1840
|
+
throughput: {
|
|
1841
|
+
instant(): IThroughputData; // Last 1 second
|
|
1842
|
+
recent(): IThroughputData; // Last 10 seconds
|
|
1843
|
+
average(): IThroughputData; // Last 60 seconds
|
|
1844
|
+
custom(seconds: number): IThroughputData;
|
|
1845
|
+
history(seconds: number): Array<IThroughputHistoryPoint>;
|
|
1846
|
+
byRoute(windowSeconds?: number): Map<string, IThroughputData>;
|
|
1847
|
+
byIP(windowSeconds?: number): Map<string, IThroughputData>;
|
|
1848
|
+
};
|
|
1849
|
+
|
|
1850
|
+
requests: {
|
|
1851
|
+
perSecond(): number;
|
|
1852
|
+
perMinute(): number;
|
|
1853
|
+
total(): number;
|
|
1854
|
+
};
|
|
1855
|
+
|
|
1856
|
+
totals: {
|
|
1857
|
+
bytesIn(): number;
|
|
1858
|
+
bytesOut(): number;
|
|
1859
|
+
connections(): number;
|
|
1860
|
+
};
|
|
1861
|
+
|
|
1862
|
+
percentiles: {
|
|
1863
|
+
connectionDuration(): { p50: number; p95: number; p99: number };
|
|
1864
|
+
bytesTransferred(): {
|
|
1865
|
+
in: { p50: number; p95: number; p99: number };
|
|
1866
|
+
out: { p50: number; p95: number; p99: number };
|
|
1867
|
+
};
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
```
|
|
1871
|
+
|
|
1872
|
+
Where `IThroughputData` is:
|
|
1873
|
+
```typescript
|
|
1874
|
+
interface IThroughputData {
|
|
1875
|
+
in: number; // Bytes per second incoming
|
|
1876
|
+
out: number; // Bytes per second outgoing
|
|
1877
|
+
}
|
|
1878
|
+
```
|
|
1879
|
+
|
|
1880
|
+
And `IThroughputHistoryPoint` is:
|
|
1881
|
+
```typescript
|
|
1882
|
+
interface IThroughputHistoryPoint {
|
|
1883
|
+
timestamp: number; // Unix timestamp in milliseconds
|
|
1884
|
+
in: number; // Bytes per second at this point
|
|
1885
|
+
out: number; // Bytes per second at this point
|
|
1886
|
+
}
|
|
1887
|
+
```
|
|
1888
|
+
|
|
1723
1889
|
## Other Components
|
|
1724
1890
|
|
|
1725
1891
|
While SmartProxy provides a unified API for most needs, you can also use individual components:
|