import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as net from 'net'; import { SmartProxy } from '../ts/index.js'; import type { IRouteConfig } from '../ts/index.js'; let proxy: SmartProxy; tap.test('setup socket handler test', async () => { // Create a simple socket handler route const routes: IRouteConfig[] = [{ name: 'echo-handler', match: { ports: 9999 // No domains restriction - matches all connections }, action: { type: 'socket-handler', socketHandler: (socket) => { console.log('Socket handler called'); // Simple echo server socket.write('ECHO SERVER\n'); socket.on('data', (data) => { console.log('Socket handler received data:', data.toString()); socket.write(`ECHO: ${data}`); }); socket.on('error', (err) => { console.error('Socket error:', err); }); } } }]; proxy = new SmartProxy({ routes, enableDetailedLogging: false }); await proxy.start(); }); tap.test('should handle socket with custom function', async () => { const client = new net.Socket(); let response = ''; await new Promise((resolve, reject) => { client.connect(9999, 'localhost', () => { console.log('Client connected to proxy'); resolve(); }); client.on('error', reject); }); // Collect data client.on('data', (data) => { console.log('Client received:', data.toString()); response += data.toString(); }); // Wait a bit for connection to stabilize await new Promise(resolve => setTimeout(resolve, 50)); // Send test data console.log('Sending test data...'); client.write('Hello World\n'); // Wait for response await new Promise(resolve => setTimeout(resolve, 200)); console.log('Total response:', response); expect(response).toContain('ECHO SERVER'); expect(response).toContain('ECHO: Hello World'); client.destroy(); }); tap.test('should handle async socket handler', async () => { // Update route with async handler await proxy.updateRoutes([{ name: 'async-handler', match: { ports: 9999 }, action: { type: 'socket-handler', socketHandler: async (socket) => { // Set up data handler first socket.on('data', async (data) => { console.log('Async handler received:', data.toString()); // Simulate async processing await new Promise(resolve => setTimeout(resolve, 10)); const processed = `PROCESSED: ${data.toString().trim().toUpperCase()}\n`; console.log('Sending:', processed); socket.write(processed); }); // Then simulate async operation await new Promise(resolve => setTimeout(resolve, 10)); socket.write('ASYNC READY\n'); } } }]); const client = new net.Socket(); let response = ''; // Collect data client.on('data', (data) => { response += data.toString(); }); await new Promise((resolve, reject) => { client.connect(9999, 'localhost', () => { // Send initial data to trigger the handler client.write('test data\n'); resolve(); }); client.on('error', reject); }); // Wait for async processing await new Promise(resolve => setTimeout(resolve, 200)); console.log('Final response:', response); expect(response).toContain('ASYNC READY'); expect(response).toContain('PROCESSED: TEST DATA'); client.destroy(); }); tap.test('should handle errors in socket handler', async () => { // Update route with error-throwing handler await proxy.updateRoutes([{ name: 'error-handler', match: { ports: 9999 }, action: { type: 'socket-handler', socketHandler: (socket) => { throw new Error('Handler error'); } } }]); const client = new net.Socket(); let connectionClosed = false; client.on('close', () => { connectionClosed = true; }); await new Promise((resolve, reject) => { client.connect(9999, 'localhost', () => { // Connection established - send data to trigger handler client.write('trigger\n'); resolve(); }); client.on('error', () => { // Ignore client errors - we expect the connection to be closed }); }); // Wait a bit await new Promise(resolve => setTimeout(resolve, 100)); // Socket should be closed due to handler error expect(connectionClosed).toEqual(true); }); tap.test('cleanup', async () => { await proxy.stop(); }); export default tap.start();