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,122 @@
import type { IRouteConfig, IRouteAction, IRouteTarget } from './models/route-types.js';
import { logger } from '../../core/utils/logger.js';
/**
* Preprocesses routes before sending them to Rust.
*
* Strips non-serializable fields (functions, callbacks) and classifies
* routes that must be handled by TypeScript (socket-handler, dynamic host/port).
*/
export class RoutePreprocessor {
/**
* Map of route name/id → original route config (with JS functions preserved).
* Used by the socket handler server to look up the original handler.
*/
private originalRoutes = new Map<string, IRouteConfig>();
/**
* Preprocess routes for the Rust binary.
*
* - Routes with `socketHandler` callbacks are marked as socket-handler type
* (Rust will relay these back to TS)
* - Routes with dynamic `host`/`port` functions are converted to socket-handler
* type (Rust relays, TS resolves the function)
* - Non-serializable fields are stripped
* - Original routes are preserved in the local map for handler lookup
*/
public preprocessForRust(routes: IRouteConfig[]): IRouteConfig[] {
this.originalRoutes.clear();
return routes.map((route, index) => this.preprocessRoute(route, index));
}
/**
* Get the original route config (with JS functions) by route name or id.
*/
public getOriginalRoute(routeKey: string): IRouteConfig | undefined {
return this.originalRoutes.get(routeKey);
}
/**
* Get all original routes that have socket handlers or dynamic functions.
*/
public getHandlerRoutes(): Map<string, IRouteConfig> {
return new Map(this.originalRoutes);
}
private preprocessRoute(route: IRouteConfig, index: number): IRouteConfig {
const routeKey = route.name || route.id || `route_${index}`;
// Check if this route needs TS-side handling
const needsTsHandling = this.routeNeedsTsHandling(route);
if (needsTsHandling) {
// Store the original route for handler lookup
this.originalRoutes.set(routeKey, route);
}
// Create a clean copy for Rust
const cleanRoute: IRouteConfig = {
...route,
action: this.cleanAction(route.action, routeKey, needsTsHandling),
};
// Ensure we have a name for handler lookup
if (!cleanRoute.name && !cleanRoute.id) {
cleanRoute.name = routeKey;
}
return cleanRoute;
}
private routeNeedsTsHandling(route: IRouteConfig): boolean {
// Socket handler routes always need TS
if (route.action.type === 'socket-handler' && route.action.socketHandler) {
return true;
}
// Routes with dynamic host/port functions need TS
if (route.action.targets) {
for (const target of route.action.targets) {
if (typeof target.host === 'function' || typeof target.port === 'function') {
return true;
}
}
}
return false;
}
private cleanAction(action: IRouteAction, routeKey: string, needsTsHandling: boolean): IRouteAction {
const cleanAction: IRouteAction = { ...action };
if (needsTsHandling) {
// Convert to socket-handler type for Rust (Rust will relay back to TS)
cleanAction.type = 'socket-handler';
// Remove the JS handler (not serializable)
delete (cleanAction as any).socketHandler;
}
// Clean targets - replace functions with static values
if (cleanAction.targets) {
cleanAction.targets = cleanAction.targets.map(t => this.cleanTarget(t));
}
return cleanAction;
}
private cleanTarget(target: IRouteTarget): IRouteTarget {
const clean: IRouteTarget = { ...target };
// Replace function host with placeholder
if (typeof clean.host === 'function') {
clean.host = 'localhost';
}
// Replace function port with placeholder
if (typeof clean.port === 'function') {
clean.port = 0;
}
return clean;
}
}