mirror of
https://github.com/tvytlx/ai-agent-deep-dive.git
synced 2026-04-03 07:34:50 +08:00
95 lines
3.8 KiB
JavaScript
95 lines
3.8 KiB
JavaScript
import { createServer } from '@pondwader/socks5-server';
|
|
import { logForDebugging } from '../utils/debug.js';
|
|
export function createSocksProxyServer(options) {
|
|
const socksServer = createServer();
|
|
socksServer.setRulesetValidator(async (conn) => {
|
|
try {
|
|
const hostname = conn.destAddress;
|
|
const port = conn.destPort;
|
|
logForDebugging(`Connection request to ${hostname}:${port}`);
|
|
const allowed = await options.filter(port, hostname);
|
|
if (!allowed) {
|
|
logForDebugging(`Connection blocked to ${hostname}:${port}`, {
|
|
level: 'error',
|
|
});
|
|
return false;
|
|
}
|
|
logForDebugging(`Connection allowed to ${hostname}:${port}`);
|
|
return true;
|
|
}
|
|
catch (error) {
|
|
logForDebugging(`Error validating connection: ${error}`, {
|
|
level: 'error',
|
|
});
|
|
return false;
|
|
}
|
|
});
|
|
return {
|
|
server: socksServer,
|
|
getPort() {
|
|
// Access the internal server to get the port
|
|
// We need to use type assertion here as the server property is private
|
|
try {
|
|
const serverInternal = socksServer?.server;
|
|
if (serverInternal && typeof serverInternal?.address === 'function') {
|
|
const address = serverInternal.address();
|
|
if (address && typeof address === 'object' && 'port' in address) {
|
|
return address.port;
|
|
}
|
|
}
|
|
}
|
|
catch (error) {
|
|
// Server might not be listening yet or property access failed
|
|
logForDebugging(`Error getting port: ${error}`, { level: 'error' });
|
|
}
|
|
return undefined;
|
|
},
|
|
listen(port, hostname) {
|
|
return new Promise((resolve, reject) => {
|
|
const listeningCallback = () => {
|
|
const actualPort = this.getPort();
|
|
if (actualPort) {
|
|
logForDebugging(`SOCKS proxy listening on ${hostname}:${actualPort}`);
|
|
resolve(actualPort);
|
|
}
|
|
else {
|
|
reject(new Error('Failed to get SOCKS proxy server port'));
|
|
}
|
|
};
|
|
socksServer.listen(port, hostname, listeningCallback);
|
|
});
|
|
},
|
|
async close() {
|
|
return new Promise((resolve, reject) => {
|
|
socksServer.close(error => {
|
|
if (error) {
|
|
// Only reject for actual errors, not for "already closed" states
|
|
// Check for common "already closed" error patterns
|
|
const errorMessage = error.message?.toLowerCase() || '';
|
|
const isAlreadyClosed = errorMessage.includes('not running') ||
|
|
errorMessage.includes('already closed') ||
|
|
errorMessage.includes('not listening');
|
|
if (!isAlreadyClosed) {
|
|
reject(error);
|
|
return;
|
|
}
|
|
}
|
|
resolve();
|
|
});
|
|
});
|
|
},
|
|
unref() {
|
|
// Access the internal server to call unref
|
|
try {
|
|
const serverInternal = socksServer?.server;
|
|
if (serverInternal && typeof serverInternal?.unref === 'function') {
|
|
serverInternal.unref();
|
|
}
|
|
}
|
|
catch (error) {
|
|
logForDebugging(`Error calling unref: ${error}`, { level: 'error' });
|
|
}
|
|
},
|
|
};
|
|
}
|
|
//# sourceMappingURL=socks-proxy.js.map
|