tasq/node_modules/agentic-flow/dist/proxy/adaptive-proxy.js

225 lines
8.3 KiB
JavaScript

/**
* Adaptive Multi-Protocol Proxy
*
* Automatically selects optimal protocol based on:
* - Client capabilities
* - Network conditions
* - Configuration priorities
*
* Fallback chain: HTTP/3 → HTTP/2 → HTTP/1.1 → WebSocket
*/
import { HTTP2Proxy } from './http2-proxy.js';
import { HTTP3Proxy } from './http3-proxy.js';
import { WebSocketProxy } from './websocket-proxy.js';
import { AnthropicToGeminiProxy } from './anthropic-to-gemini.js';
import { logger } from '../utils/logger.js';
export class AdaptiveProxy {
config;
servers = [];
isRunning = false;
constructor(config) {
this.config = {
enableHTTP1: true, // Always enabled
enableHTTP2: config.enableHTTP2 ?? true,
enableHTTP3: config.enableHTTP3 ?? false, // Disabled by default (requires QUIC)
enableWebSocket: config.enableWebSocket ?? true,
http1Port: config.http1Port || 3000,
http2Port: config.http2Port || 3001,
http3Port: config.http3Port || 4433,
wsPort: config.wsPort || 8080,
...config
};
logger.info('Adaptive proxy created', {
protocols: this.getEnabledProtocols()
});
}
getEnabledProtocols() {
const protocols = [];
if (this.config.enableHTTP3)
protocols.push('HTTP/3');
if (this.config.enableHTTP2)
protocols.push('HTTP/2');
if (this.config.enableHTTP1)
protocols.push('HTTP/1.1');
if (this.config.enableWebSocket)
protocols.push('WebSocket');
return protocols;
}
async start() {
console.log('\n🚀 Starting Adaptive Multi-Protocol Proxy...\n');
// Try HTTP/3 first (fastest)
if (this.config.enableHTTP3) {
try {
const http3 = new HTTP3Proxy({
port: this.config.http3Port,
cert: this.config.cert,
key: this.config.key,
geminiApiKey: this.config.geminiApiKey,
geminiBaseUrl: this.config.geminiBaseUrl
});
await http3.start();
this.servers.push({
protocol: 'HTTP/3',
port: this.config.http3Port,
url: `https://localhost:${this.config.http3Port}`,
proxy: http3
});
console.log(`✅ HTTP/3 (QUIC) → Port ${this.config.http3Port} (fastest, 50-70% improvement)`);
}
catch (error) {
logger.warn('HTTP/3 unavailable, skipping', { error: error.message });
console.log(`⚠️ HTTP/3 (QUIC) → Unavailable (${error.message})`);
}
}
// Try HTTP/2 next
if (this.config.enableHTTP2) {
try {
const http2 = new HTTP2Proxy({
port: this.config.http2Port,
cert: this.config.cert,
key: this.config.key,
geminiApiKey: this.config.geminiApiKey,
geminiBaseUrl: this.config.geminiBaseUrl
});
await http2.start();
this.servers.push({
protocol: 'HTTP/2',
port: this.config.http2Port,
url: `https://localhost:${this.config.http2Port}`,
proxy: http2
});
console.log(`✅ HTTP/2 → Port ${this.config.http2Port} (30-50% improvement)`);
}
catch (error) {
logger.warn('HTTP/2 unavailable, skipping', { error: error.message });
console.log(`⚠️ HTTP/2 → Unavailable (${error.message})`);
}
}
// HTTP/1.1 (always available)
if (this.config.enableHTTP1) {
try {
const http1 = new AnthropicToGeminiProxy({
geminiApiKey: this.config.geminiApiKey,
geminiBaseUrl: this.config.geminiBaseUrl,
defaultModel: 'gemini-2.0-flash-exp'
});
http1.start(this.config.http1Port);
this.servers.push({
protocol: 'HTTP/1.1',
port: this.config.http1Port,
url: `http://localhost:${this.config.http1Port}`,
proxy: http1
});
console.log(`✅ HTTP/1.1 → Port ${this.config.http1Port} (baseline, always available)`);
}
catch (error) {
logger.error('HTTP/1.1 failed to start', { error: error.message });
throw error; // HTTP/1.1 failure is fatal
}
}
// WebSocket fallback for unreliable connections
if (this.config.enableWebSocket) {
try {
const ws = new WebSocketProxy({
port: this.config.wsPort,
geminiApiKey: this.config.geminiApiKey,
geminiBaseUrl: this.config.geminiBaseUrl
});
await ws.start();
this.servers.push({
protocol: 'WebSocket',
port: this.config.wsPort,
url: `ws://localhost:${this.config.wsPort}`,
proxy: ws
});
console.log(`✅ WebSocket → Port ${this.config.wsPort} (mobile/unstable connections)`);
}
catch (error) {
logger.warn('WebSocket unavailable, skipping', { error: error.message });
console.log(`⚠️ WebSocket → Unavailable (${error.message})`);
}
}
this.isRunning = true;
console.log(`\n📊 Active Protocols: ${this.servers.length}/${this.getEnabledProtocols().length}`);
console.log(`\n💡 Usage:`);
this.servers.forEach(s => {
console.log(` ${s.protocol.padEnd(12)} → curl ${s.url}/health`);
});
console.log('');
logger.info('Adaptive proxy started', {
activeServers: this.servers.length,
protocols: this.servers.map(s => s.protocol)
});
return this.servers;
}
async stop() {
if (!this.isRunning)
return;
console.log('\n🛑 Stopping all proxy servers...\n');
for (const server of this.servers) {
try {
if (server.proxy.stop) {
await server.proxy.stop();
}
console.log(`✅ Stopped ${server.protocol}`);
}
catch (error) {
logger.error(`Failed to stop ${server.protocol}`, { error: error.message });
}
}
this.servers = [];
this.isRunning = false;
logger.info('Adaptive proxy stopped');
console.log('\n✅ All proxy servers stopped\n');
}
getServers() {
return [...this.servers];
}
getStatus() {
return {
isRunning: this.isRunning,
servers: this.servers.map(s => ({
protocol: s.protocol,
port: s.port,
url: s.url
})),
enabledProtocols: this.getEnabledProtocols()
};
}
}
// CLI entry point
if (import.meta.url === `file://${process.argv[1]}`) {
const geminiApiKey = process.env.GOOGLE_GEMINI_API_KEY;
if (!geminiApiKey) {
console.error('❌ Error: GOOGLE_GEMINI_API_KEY environment variable required');
process.exit(1);
}
const proxy = new AdaptiveProxy({
enableHTTP1: true,
enableHTTP2: true,
enableHTTP3: false, // Requires QUIC setup
enableWebSocket: true,
http1Port: 3000,
http2Port: 3001,
http3Port: 4433,
wsPort: 8080,
cert: process.env.TLS_CERT,
key: process.env.TLS_KEY,
geminiApiKey,
geminiBaseUrl: process.env.GEMINI_BASE_URL
});
proxy.start().catch((error) => {
console.error('❌ Failed to start adaptive proxy:', error);
process.exit(1);
});
// Graceful shutdown
process.on('SIGINT', async () => {
await proxy.stop();
process.exit(0);
});
process.on('SIGTERM', async () => {
await proxy.stop();
process.exit(0);
});
}
//# sourceMappingURL=adaptive-proxy.js.map