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:
122
ts/proxies/smart-proxy/route-preprocessor.ts
Normal file
122
ts/proxies/smart-proxy/route-preprocessor.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user