wireshade 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +111 -0
- package/Cargo.lock +1238 -0
- package/Cargo.toml +27 -0
- package/LICENSE +21 -0
- package/README.de.md +256 -0
- package/README.es.md +109 -0
- package/README.fr.md +109 -0
- package/README.md +258 -0
- package/README.zh.md +109 -0
- package/build.rs +5 -0
- package/examples/01_quickstart.js +36 -0
- package/examples/02_http_request.js +44 -0
- package/examples/03_https_custom_dns.js +47 -0
- package/examples/04_tcp_socket.js +50 -0
- package/examples/05_internet_routing.js +33 -0
- package/examples/06_simple_server.js +40 -0
- package/examples/07_express_app.js +37 -0
- package/examples/08_local_forwarding.js +30 -0
- package/examples/09_reconnect_config.js +128 -0
- package/examples/10_remote_forwarding.js +63 -0
- package/examples/README.md +54 -0
- package/examples/_legacy_easy_api.js +53 -0
- package/examples/wireguard.conf +8 -0
- package/index.d.ts +0 -0
- package/index.js +29 -0
- package/lib/agent.js +116 -0
- package/lib/client.js +548 -0
- package/lib/config_parser.js +77 -0
- package/lib/server.js +121 -0
- package/package.json +31 -0
- package/parallel_output.txt +0 -0
- package/src/lib.rs +841 -0
- package/wireshade.darwin-arm64.node +0 -0
- package/wireshade.darwin-x64.node +0 -0
- package/wireshade.linux-arm-gnueabihf.node +0 -0
- package/wireshade.linux-arm64-gnu.node +0 -0
- package/wireshade.linux-x64-gnu.node +0 -0
- package/wireshade.win32-x64-msvc.node +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const { WireShade } = require('../index');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Example: TCP Port Forwarding
|
|
6
|
+
* Forwards localhost:8080 -> 10.0.0.5:80 via VPN
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
async function examplePortForward() {
|
|
10
|
+
const gw = new WireShade(path.join(__dirname, 'wireguard.conf'));
|
|
11
|
+
|
|
12
|
+
gw.on('connect', async () => {
|
|
13
|
+
console.log("VPN Connected.");
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const server = await gw.forwardLocal(8080, '10.0.0.5', 80);
|
|
17
|
+
|
|
18
|
+
console.log(`Forwarding localhost:8080 -> 10.0.0.5:80`);
|
|
19
|
+
console.log("Press Ctrl+C to stop.");
|
|
20
|
+
|
|
21
|
+
// server is a net.Server
|
|
22
|
+
server.on('error', (e) => console.error("Server error:", e.message));
|
|
23
|
+
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error("Failed to start forwarding:", err.message);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
examplePortForward();
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WireShadeClient Reconnection Demo
|
|
3
|
+
*
|
|
4
|
+
* Zeigt die automatische Reconnection-Logik mit Events und Konfiguration.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { WireShade, ConnectionState } = require('../index');
|
|
8
|
+
const https = require('https');
|
|
9
|
+
|
|
10
|
+
const { readWireGuardConfig } = require('../lib/config_parser');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const wireguardConfig = readWireGuardConfig(path.join(__dirname, 'wireguard.conf'));
|
|
14
|
+
|
|
15
|
+
const config = {
|
|
16
|
+
wireguard: wireguardConfig,
|
|
17
|
+
|
|
18
|
+
logging: true,
|
|
19
|
+
|
|
20
|
+
// Reconnection configuration
|
|
21
|
+
reconnect: {
|
|
22
|
+
enabled: true, // Auto-reconnect on disconnect
|
|
23
|
+
maxAttempts: 5, // Max attempts (0 = infinite)
|
|
24
|
+
delay: 1000, // Initial delay: 1 second
|
|
25
|
+
maxDelay: 30000, // Max delay: 30 seconds
|
|
26
|
+
backoffMultiplier: 2, // Double delay each attempt
|
|
27
|
+
healthCheckInterval: 60000 // Check every 60 seconds
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
hosts: {
|
|
31
|
+
'internal.service.lan': '10.0.0.5'
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
async function main() {
|
|
36
|
+
console.log('=== WireShadeClient Reconnection Demo ===\n');
|
|
37
|
+
|
|
38
|
+
const client = new WireShade(config);
|
|
39
|
+
|
|
40
|
+
// Event: State changes
|
|
41
|
+
client.on('stateChange', (state) => {
|
|
42
|
+
const stateEmoji = {
|
|
43
|
+
[ConnectionState.DISCONNECTED]: '🔴',
|
|
44
|
+
[ConnectionState.CONNECTING]: '🟡',
|
|
45
|
+
[ConnectionState.CONNECTED]: '🟢',
|
|
46
|
+
[ConnectionState.RECONNECTING]: '🟠'
|
|
47
|
+
};
|
|
48
|
+
console.log(`[State] ${stateEmoji[state] || '⚪'} ${state}`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Event: Connected
|
|
52
|
+
client.on('connect', () => {
|
|
53
|
+
console.log('[Event] ✅ Verbunden!');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Event: Disconnected
|
|
57
|
+
client.on('disconnect', (err) => {
|
|
58
|
+
console.log('[Event] ❌ Verbindung getrennt:', err?.message || 'Unknown');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Event: Reconnecting
|
|
62
|
+
client.on('reconnecting', (attempt) => {
|
|
63
|
+
console.log(`[Event] 🔄 Reconnect Versuch ${attempt}...`);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Event: Reconnected
|
|
67
|
+
client.on('reconnect', () => {
|
|
68
|
+
console.log('[Event] ✅ Wiederverbunden!');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Event: Reconnect failed
|
|
72
|
+
client.on('reconnectFailed', () => {
|
|
73
|
+
console.log('[Event] ❌ Reconnection fehlgeschlagen nach max Versuchen');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Event: Health check
|
|
77
|
+
client.on('healthCheck', () => {
|
|
78
|
+
console.log('[Health] 💓 Health check...');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Wait for initial connection
|
|
82
|
+
await new Promise(resolve => setTimeout(resolve, 4000));
|
|
83
|
+
|
|
84
|
+
// Test: Make a request
|
|
85
|
+
console.log('\n--- Test Request ---');
|
|
86
|
+
try {
|
|
87
|
+
const response = await makeRequest(client, 'https://ifconfig.me/ip');
|
|
88
|
+
console.log('Externe IP:', response.trim());
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.log('Request fehlgeschlagen:', err.message);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Demo: Manual reconnect
|
|
94
|
+
console.log('\n--- Manual Reconnect Test ---');
|
|
95
|
+
console.log('Drücke Ctrl+C um zu beenden.\n');
|
|
96
|
+
|
|
97
|
+
// Keep running
|
|
98
|
+
setInterval(async () => {
|
|
99
|
+
if (client.connected) {
|
|
100
|
+
console.log(`[${new Date().toLocaleTimeString()}] Status: Verbunden`);
|
|
101
|
+
} else {
|
|
102
|
+
console.log(`[${new Date().toLocaleTimeString()}] Status: ${client.state}`);
|
|
103
|
+
}
|
|
104
|
+
}, 10000);
|
|
105
|
+
|
|
106
|
+
// Graceful shutdown
|
|
107
|
+
process.on('SIGINT', () => {
|
|
108
|
+
console.log('\n\nShutting down...');
|
|
109
|
+
client.close();
|
|
110
|
+
process.exit(0);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function makeRequest(client, url) {
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
const req = https.get(url, { agent: client.getHttpsAgent() }, (res) => {
|
|
117
|
+
let data = '';
|
|
118
|
+
res.on('data', chunk => data += chunk);
|
|
119
|
+
res.on('end', () => resolve(data));
|
|
120
|
+
});
|
|
121
|
+
req.on('error', reject);
|
|
122
|
+
req.setTimeout(10000, () => {
|
|
123
|
+
req.destroy(new Error('Timeout'));
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const { WireShade } = require('../index');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const http = require('http');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Example: Remote Forwarding (Reverse Port Forwarding)
|
|
7
|
+
*
|
|
8
|
+
* Scenario:
|
|
9
|
+
* You have a service running on your local LAN (e.g., a local printer web interface,
|
|
10
|
+
* or a development server on another machine) at '192.168.1.50:80'.
|
|
11
|
+
*
|
|
12
|
+
* You want to make this service accessible to everyone in the VPN at '10.0.0.2:8080'.
|
|
13
|
+
*
|
|
14
|
+
* Flow: [VPN User] -> [WireShade VPN IP:8080] -> [WireShade] -> [Local LAN IP:80]
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
console.log("=== WireShade Remote Forwarding Demo ===");
|
|
19
|
+
|
|
20
|
+
// 1. Initialize
|
|
21
|
+
const gw = new WireShade(path.join(__dirname, 'wireguard.conf'));
|
|
22
|
+
|
|
23
|
+
gw.on('connect', async () => {
|
|
24
|
+
console.log(`VPN Connected as ${gw.config.wireguard.sourceIp}`);
|
|
25
|
+
|
|
26
|
+
// Mock a "local service" for demonstration purposes
|
|
27
|
+
// In reality, this would be an existing service on your machine or network.
|
|
28
|
+
startMockLocalService(3000);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// 2. Start Forwarding
|
|
32
|
+
// Listen on VPN Port 8080 -> Forward to localhost:3000
|
|
33
|
+
const vpnPort = 8080;
|
|
34
|
+
const localTargetHost = 'localhost';
|
|
35
|
+
const localTargetPort = 3000;
|
|
36
|
+
|
|
37
|
+
await gw.forwardRemote(vpnPort, localTargetHost, localTargetPort);
|
|
38
|
+
|
|
39
|
+
console.log(`\n✅ Forwarding Active!`);
|
|
40
|
+
console.log(`Traffic to VPN ${gw.config.wireguard.sourceIp}:${vpnPort} is now forwarded to ${localTargetHost}:${localTargetPort}`);
|
|
41
|
+
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.error("Forwarding failed:", err);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
gw.on('error', console.error);
|
|
48
|
+
await gw.start();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function startMockLocalService(port) {
|
|
52
|
+
const server = http.createServer((req, res) => {
|
|
53
|
+
console.log(`[Local Service] Received request: ${req.method} ${req.url}`);
|
|
54
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
55
|
+
res.end(`Hello from the Local Service! You reached me via VPN.`);
|
|
56
|
+
});
|
|
57
|
+
server.listen(port, () => {
|
|
58
|
+
console.log(`[Local Service] Running on port ${port}`);
|
|
59
|
+
});
|
|
60
|
+
return server;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
main();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# WireShade Examples
|
|
2
|
+
|
|
3
|
+
This directory contains example scripts demonstrating various capabilities of the WireShade library.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Ensure you have a valid `wireguard.conf` in this directory (or update the scripts to point to one).
|
|
8
|
+
2. Run the examples using `node examples/<filename>`.
|
|
9
|
+
|
|
10
|
+
## Available Examples
|
|
11
|
+
|
|
12
|
+
### 1. Quickstart (`01_quickstart.js`)
|
|
13
|
+
The "Hello World" of WireShade. Shows how to initialize the connection, perform a simple request, and start a listener.
|
|
14
|
+
- **Run:** `node examples/01_quickstart.js`
|
|
15
|
+
|
|
16
|
+
### 2. HTTP Request (`02_http_request.js`)
|
|
17
|
+
Performs a simple HTTP GET request to an internal web server using the simplified `gw.get()` API.
|
|
18
|
+
- **Run:** `node examples/02_http_request.js`
|
|
19
|
+
|
|
20
|
+
### 3. HTTPS & Custom DNS (`03_https_custom_dns.js`)
|
|
21
|
+
Demonstrates how to access an HTTPS server with a custom hostname (`internal.service.lan`) mapped to an internal IP.
|
|
22
|
+
- **Run:** `node examples/03_https_custom_dns.js`
|
|
23
|
+
|
|
24
|
+
### 4. Raw TCP Socket (`04_tcp_socket.js`)
|
|
25
|
+
Shows low-level usage to send raw data bytes (HTTP request manually constructed) and receive raw bytes, bypassing higher-level helpers.
|
|
26
|
+
- **Run:** `node examples/04_tcp_socket.js`
|
|
27
|
+
|
|
28
|
+
### 5. Internet Routing (`05_internet_routing.js`)
|
|
29
|
+
Tests routing to the public internet by fetching your IP from `ifconfig.me`. Confirms that traffic exits via the WireGuard VPN gateway.
|
|
30
|
+
- **Run:** `node examples/05_internet_routing.js`
|
|
31
|
+
|
|
32
|
+
### 6. Simple Server (`06_simple_server.js`)
|
|
33
|
+
Host a basic HTTP server inside the VPN tunnel.
|
|
34
|
+
- **Run:** `node examples/06_simple_server.js`
|
|
35
|
+
|
|
36
|
+
### 7. Express App (`07_express_app.js`)
|
|
37
|
+
Run a full Express.js application and make it accessible via the VPN tunnel (Reverse Tunneling).
|
|
38
|
+
- **Run:** `node examples/07_express_app.js`
|
|
39
|
+
|
|
40
|
+
### 8. Local Forwarding (`08_local_forwarding.js`)
|
|
41
|
+
Starts a local TCP server on port `8080` that forwards all traffic to an internal host (`10.0.0.5:80`).
|
|
42
|
+
- **Run:** `node examples/08_local_forwarding.js`
|
|
43
|
+
|
|
44
|
+
### 9. Advanced Reconnect (`09_reconnect_config.js`)
|
|
45
|
+
Demonstrates reconnection logic, health checks, and event monitoring.
|
|
46
|
+
- **Run:** `node examples/09_reconnect_config.js`
|
|
47
|
+
|
|
48
|
+
### 10. Remote Forwarding (`10_remote_forwarding.js`)
|
|
49
|
+
Exposes a service running on your local machine (or local network) to the VPN. Traffic sent to a specific VPN port is forwarded to the local target.
|
|
50
|
+
- **Run:** `node examples/10_remote_forwarding.js`
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
All examples read from `wireguard.conf` in this directory. Ensure this file contains your valid Client configuration.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const { WireShadeClient } = require('../index');
|
|
2
|
+
const https = require('https');
|
|
3
|
+
|
|
4
|
+
async function testEasyApi() {
|
|
5
|
+
console.log("--- WireShade Easy API Test (Quiet Mode) ---");
|
|
6
|
+
|
|
7
|
+
const client = new WireShadeClient({
|
|
8
|
+
wireguard: {
|
|
9
|
+
privateKey: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
10
|
+
peerPublicKey: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=",
|
|
11
|
+
presharedKey: "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=",
|
|
12
|
+
endpoint: "203.0.113.1:51820",
|
|
13
|
+
sourceIp: "10.0.0.2"
|
|
14
|
+
},
|
|
15
|
+
logging: false, // DISABLES INTERNAL LOGS
|
|
16
|
+
onConnect: () => {
|
|
17
|
+
console.log("\n>>> EVENT: WireGuard Connection Ready! <<<");
|
|
18
|
+
},
|
|
19
|
+
onDisconnect: () => {
|
|
20
|
+
console.log(">>> EVENT: WireGuard Connection Closed! <<<");
|
|
21
|
+
},
|
|
22
|
+
hosts: {
|
|
23
|
+
'internal.service.lan': '10.0.0.5'
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Wait a bit to ensure onConnect fired (just for demo flow)
|
|
28
|
+
await new Promise(r => setTimeout(r, 200));
|
|
29
|
+
|
|
30
|
+
const target = 'https://internal.service.lan';
|
|
31
|
+
console.log(`\n[HTTPS] Fetching ${target}...`);
|
|
32
|
+
|
|
33
|
+
https.get(target, { agent: client.getHttpsAgent() }, (res) => {
|
|
34
|
+
console.log(`[Response] Status: ${res.statusCode}`);
|
|
35
|
+
// res.on('data', d => process.stdout.write(d)); // Suppress body for cleaner output
|
|
36
|
+
console.log(`[Response] Headers received.`);
|
|
37
|
+
|
|
38
|
+
// Start Port Forwarding after request
|
|
39
|
+
startForwarding(client);
|
|
40
|
+
}).on('error', console.error);
|
|
41
|
+
|
|
42
|
+
async function startForwarding(client) {
|
|
43
|
+
try {
|
|
44
|
+
await client.forwardLocal(9090, '10.0.0.5', 80);
|
|
45
|
+
console.log("\n[Forward] Listening on localhost:9090 -> 10.0.0.5:80");
|
|
46
|
+
console.log("[Forward] Speed test: Open http://localhost:9090 (Should be fast now!)");
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.error(e);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
testEasyApi();
|
package/index.d.ts
ADDED
|
File without changes
|
package/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
let binding;
|
|
5
|
+
try {
|
|
6
|
+
binding = require('./wireshade.node');
|
|
7
|
+
} catch (e) {
|
|
8
|
+
try {
|
|
9
|
+
binding = require('./wireshade.win32-x64-msvc.node');
|
|
10
|
+
} catch (e2) {
|
|
11
|
+
throw new Error('Could not load native binding');
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { WireShadeAgent } = require('./lib/agent');
|
|
16
|
+
const { WireShadeClient, ConnectionState } = require('./lib/client');
|
|
17
|
+
const { WireShadeServer } = require('./lib/server');
|
|
18
|
+
const { parseWireGuardConfig, readWireGuardConfig } = require('./lib/config_parser');
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
WireShade: WireShadeClient, // The high-level client is the main export
|
|
22
|
+
NativeWireShade: binding.WireShade,
|
|
23
|
+
WireShadeClient,
|
|
24
|
+
WireShadeAgent,
|
|
25
|
+
WireShadeServer,
|
|
26
|
+
ConnectionState,
|
|
27
|
+
parseConfig: parseWireGuardConfig,
|
|
28
|
+
readConfig: readWireGuardConfig
|
|
29
|
+
};
|
package/lib/agent.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const { Duplex } = require('stream');
|
|
3
|
+
const dns = require('dns');
|
|
4
|
+
|
|
5
|
+
class WireShadeAgent extends http.Agent {
|
|
6
|
+
constructor(wireShade, options) {
|
|
7
|
+
super(options);
|
|
8
|
+
this.gw = wireShade;
|
|
9
|
+
this.options = options || {};
|
|
10
|
+
|
|
11
|
+
// Configure Logger
|
|
12
|
+
// Priority: options.logger -> console.log (unless logging===false)
|
|
13
|
+
this.log = this.options.logger || (this.options.logging === false ? () => { } : console.log);
|
|
14
|
+
this.error = this.options.logger || console.error;
|
|
15
|
+
}
|
|
16
|
+
createConnection(options, cb) {
|
|
17
|
+
const { host, port } = options;
|
|
18
|
+
const log = this.log;
|
|
19
|
+
const error = this.error;
|
|
20
|
+
|
|
21
|
+
log(`[Agent] Connecting to ${host}:${port}`);
|
|
22
|
+
|
|
23
|
+
const stream = new Duplex({
|
|
24
|
+
allowHalfOpen: true,
|
|
25
|
+
read(size) { },
|
|
26
|
+
write(chunk, encoding, callback) {
|
|
27
|
+
log(`[AgentStream] write called with ${chunk.length} bytes`);
|
|
28
|
+
if (this.connection) {
|
|
29
|
+
log(`[AgentStream] Sending immediately...`);
|
|
30
|
+
this.connection.send(chunk).then(() => {
|
|
31
|
+
log(`[AgentStream] Send completed for ${chunk.length} bytes`);
|
|
32
|
+
callback();
|
|
33
|
+
}).catch((err) => {
|
|
34
|
+
error(`[AgentStream] Send error:`, err);
|
|
35
|
+
callback(err);
|
|
36
|
+
});
|
|
37
|
+
} else {
|
|
38
|
+
log(`[AgentStream] Buffering - connection not ready yet`);
|
|
39
|
+
if (!this.pendingBuffer) this.pendingBuffer = [];
|
|
40
|
+
this.pendingBuffer.push({ chunk, callback });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Mock Socket methods required by http.Agent/ClientRequest
|
|
46
|
+
stream.setTimeout = (msecs, callback) => {
|
|
47
|
+
if (callback) stream.once('timeout', callback);
|
|
48
|
+
return stream;
|
|
49
|
+
};
|
|
50
|
+
stream.setNoDelay = (enable) => stream;
|
|
51
|
+
stream.setKeepAlive = (enable, initialDelay) => stream;
|
|
52
|
+
stream.ref = () => stream;
|
|
53
|
+
stream.unref = () => stream;
|
|
54
|
+
|
|
55
|
+
// Use custom lookup if provided in options (Standard node http.Agent behavior), else default dns.lookup
|
|
56
|
+
const lookup = options.lookup || dns.lookup;
|
|
57
|
+
|
|
58
|
+
lookup(host, { family: 4 }, (err, address, family) => {
|
|
59
|
+
if (err) {
|
|
60
|
+
return cb(err);
|
|
61
|
+
}
|
|
62
|
+
log(`[Agent] Resolved ${host} to ${address}`);
|
|
63
|
+
|
|
64
|
+
this.gw.connect(address, parseInt(port),
|
|
65
|
+
(err, data) => {
|
|
66
|
+
const buffer = data || (Buffer.isBuffer(err) ? err : null);
|
|
67
|
+
if (buffer) {
|
|
68
|
+
log(`[Agent] Received ${buffer.length} bytes via connection`);
|
|
69
|
+
stream.push(buffer);
|
|
70
|
+
} else if (err && !data) {
|
|
71
|
+
error('[Agent] Receive error:', err);
|
|
72
|
+
stream.destroy(err);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
() => {
|
|
76
|
+
stream.push(null);
|
|
77
|
+
}
|
|
78
|
+
).then(conn => {
|
|
79
|
+
log(`[Agent] Connected! Setting stream.connection...`);
|
|
80
|
+
stream.connection = conn;
|
|
81
|
+
stream.emit('connect');
|
|
82
|
+
|
|
83
|
+
log(`[Agent] Checking pendingBuffer: ${stream.pendingBuffer ? stream.pendingBuffer.length + ' items' : 'none'}`);
|
|
84
|
+
if (stream.pendingBuffer && stream.pendingBuffer.length > 0) {
|
|
85
|
+
log(`[AgentStream] Flushing ${stream.pendingBuffer.length} buffered chunks`);
|
|
86
|
+
const flushPromises = stream.pendingBuffer.map(({ chunk, callback }) => {
|
|
87
|
+
log(`[AgentStream] Flushing chunk of ${chunk.length} bytes...`);
|
|
88
|
+
return conn.send(chunk).then(() => {
|
|
89
|
+
log(`[AgentStream] Flush completed for ${chunk.length} bytes`);
|
|
90
|
+
callback();
|
|
91
|
+
}).catch(err => {
|
|
92
|
+
error(`[AgentStream] Flush error:`, err);
|
|
93
|
+
callback(err);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
stream.pendingBuffer = null;
|
|
97
|
+
Promise.all(flushPromises).then(() => {
|
|
98
|
+
log(`[Agent] All buffered data flushed, calling cb`);
|
|
99
|
+
if (cb) cb(null, stream);
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
log(`[Agent] No buffered data, calling cb immediately`);
|
|
103
|
+
if (cb) cb(null, stream);
|
|
104
|
+
}
|
|
105
|
+
}).catch(err => {
|
|
106
|
+
error('[Agent] Connection failed:', err.message, err.code, err);
|
|
107
|
+
if (cb) cb(err);
|
|
108
|
+
else stream.emit('error', err);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return stream;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = { WireShadeAgent };
|