feat(rustproxy): introduce a Rust-powered proxy engine and workspace with core crates for proxy functionality, ACME/TLS support, passthrough and HTTP proxies, metrics, nftables integration, routing/security, management IPC, tests, and README updates

This commit is contained in:
2026-02-09 10:55:46 +00:00
parent a31fee41df
commit 1df3b7af4a
151 changed files with 16927 additions and 19432 deletions

View File

@@ -0,0 +1,136 @@
import type { IMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
import type { RustProxyBridge } from './rust-proxy-bridge.js';
/**
* Adapts Rust JSON metrics to the IMetrics interface.
*
* Polls the Rust binary periodically via the bridge and caches the result.
* All IMetrics getters read from the cache synchronously.
* Fields not yet in Rust (percentiles, per-IP, history) return zero/empty.
*/
export class RustMetricsAdapter implements IMetrics {
private bridge: RustProxyBridge;
private cache: any = null;
private pollTimer: ReturnType<typeof setInterval> | null = null;
private pollIntervalMs: number;
// Cumulative totals tracked across polls
private cumulativeBytesIn = 0;
private cumulativeBytesOut = 0;
private cumulativeConnections = 0;
constructor(bridge: RustProxyBridge, pollIntervalMs = 1000) {
this.bridge = bridge;
this.pollIntervalMs = pollIntervalMs;
}
public startPolling(): void {
if (this.pollTimer) return;
this.pollTimer = setInterval(async () => {
try {
this.cache = await this.bridge.getMetrics();
// Update cumulative totals
if (this.cache) {
this.cumulativeBytesIn = this.cache.totalBytesIn ?? this.cache.total_bytes_in ?? 0;
this.cumulativeBytesOut = this.cache.totalBytesOut ?? this.cache.total_bytes_out ?? 0;
this.cumulativeConnections = this.cache.totalConnections ?? this.cache.total_connections ?? 0;
}
} catch {
// Ignore poll errors (bridge may be shutting down)
}
}, this.pollIntervalMs);
if (this.pollTimer.unref) {
this.pollTimer.unref();
}
}
public stopPolling(): void {
if (this.pollTimer) {
clearInterval(this.pollTimer);
this.pollTimer = null;
}
}
// --- IMetrics implementation ---
public connections = {
active: (): number => {
return this.cache?.activeConnections ?? this.cache?.active_connections ?? 0;
},
total: (): number => {
return this.cumulativeConnections;
},
byRoute: (): Map<string, number> => {
return new Map();
},
byIP: (): Map<string, number> => {
return new Map();
},
topIPs: (_limit?: number): Array<{ ip: string; count: number }> => {
return [];
},
};
public throughput = {
instant: (): IThroughputData => {
return { in: this.cache?.bytesInPerSecond ?? 0, out: this.cache?.bytesOutPerSecond ?? 0 };
},
recent: (): IThroughputData => {
return this.throughput.instant();
},
average: (): IThroughputData => {
return this.throughput.instant();
},
custom: (_seconds: number): IThroughputData => {
return this.throughput.instant();
},
history: (_seconds: number): Array<IThroughputHistoryPoint> => {
return [];
},
byRoute: (_windowSeconds?: number): Map<string, IThroughputData> => {
return new Map();
},
byIP: (_windowSeconds?: number): Map<string, IThroughputData> => {
return new Map();
},
};
public requests = {
perSecond: (): number => {
return this.cache?.requestsPerSecond ?? 0;
},
perMinute: (): number => {
return (this.cache?.requestsPerSecond ?? 0) * 60;
},
total: (): number => {
return this.cache?.totalRequests ?? this.cache?.total_requests ?? 0;
},
};
public totals = {
bytesIn: (): number => {
return this.cumulativeBytesIn;
},
bytesOut: (): number => {
return this.cumulativeBytesOut;
},
connections: (): number => {
return this.cumulativeConnections;
},
};
public percentiles = {
connectionDuration: (): { p50: number; p95: number; p99: number } => {
return { p50: 0, p95: 0, p99: 0 };
},
bytesTransferred: (): {
in: { p50: number; p95: number; p99: number };
out: { p50: number; p95: number; p99: number };
} => {
return {
in: { p50: 0, p95: 0, p99: 0 },
out: { p50: 0, p95: 0, p99: 0 },
};
},
};
}