2020117-agent 0.6.7 → 0.6.8
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/dist/agent.js +1 -0
- package/dist/session.js +95 -9
- package/dist/swarm.d.ts +1 -0
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -919,6 +919,7 @@ async function startSwarmListener(label) {
|
|
|
919
919
|
sats_per_minute: satsPerMinute,
|
|
920
920
|
payment_method: paymentMethod,
|
|
921
921
|
pubkey: state.sovereignKeys?.pubkey,
|
|
922
|
+
proxy_mode: proxyMode,
|
|
922
923
|
});
|
|
923
924
|
if (proxyMode) {
|
|
924
925
|
if (billingAmount <= 0 || (!LIGHTNING_ADDRESS && !state.nwcParsed)) {
|
package/dist/session.js
CHANGED
|
@@ -50,6 +50,7 @@ import { randomBytes } from 'crypto';
|
|
|
50
50
|
import { createServer } from 'http';
|
|
51
51
|
import { createInterface } from 'readline';
|
|
52
52
|
import { mkdirSync, writeFileSync } from 'fs';
|
|
53
|
+
import * as net from 'net';
|
|
53
54
|
import { WebSocketServer, WebSocket as WsWebSocket } from 'ws';
|
|
54
55
|
// --- Config ---
|
|
55
56
|
const KIND = Number(process.env.DVM_KIND) || 5200;
|
|
@@ -87,6 +88,8 @@ const state = {
|
|
|
87
88
|
startedAt: 0,
|
|
88
89
|
httpServer: null,
|
|
89
90
|
shuttingDown: false,
|
|
91
|
+
isProxyMode: false,
|
|
92
|
+
proxyReady: null,
|
|
90
93
|
pendingRequests: new Map(),
|
|
91
94
|
chunkBuffers: new Map(),
|
|
92
95
|
activeWebSockets: new Map(),
|
|
@@ -195,7 +198,12 @@ function setupMessageHandler() {
|
|
|
195
198
|
try {
|
|
196
199
|
const { preimage } = await nwcPayInvoice(nwcParsed, msg.bolt11);
|
|
197
200
|
state.totalSpent += amount;
|
|
198
|
-
|
|
201
|
+
if (state.isProxyMode) {
|
|
202
|
+
log(`Paid ${amount} sats — activating TCP proxy...`);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
log(`Paid ${amount} sats via NWC (total: ${state.totalSpent}, ~${estimatedMinutesLeft()} min left)`);
|
|
206
|
+
}
|
|
199
207
|
state.node.send(state.socket, {
|
|
200
208
|
type: 'session_tick_ack',
|
|
201
209
|
id: msg.id,
|
|
@@ -203,6 +211,11 @@ function setupMessageHandler() {
|
|
|
203
211
|
preimage,
|
|
204
212
|
amount,
|
|
205
213
|
});
|
|
214
|
+
// Proxy mode: payment done, signal TCP pipe is ready
|
|
215
|
+
if (state.isProxyMode && state.proxyReady) {
|
|
216
|
+
state.proxyReady();
|
|
217
|
+
state.proxyReady = null;
|
|
218
|
+
}
|
|
206
219
|
}
|
|
207
220
|
catch (e) {
|
|
208
221
|
warn(`NWC invoice payment failed: ${e.message} — ending session`);
|
|
@@ -351,6 +364,57 @@ function startHttpProxy() {
|
|
|
351
364
|
});
|
|
352
365
|
});
|
|
353
366
|
}
|
|
367
|
+
// --- 4a. TCP proxy (proxy mode) ---
|
|
368
|
+
// After payment, the Hyperswarm socket becomes a raw TCP pipe to provider's backend.
|
|
369
|
+
// We start a local TCP server and forward bytes between local clients and the provider socket.
|
|
370
|
+
function startTcpProxy() {
|
|
371
|
+
return new Promise((resolve, reject) => {
|
|
372
|
+
const rawSocket = state.socket;
|
|
373
|
+
// Remove SwarmNode's JSON framing — from here on it's raw bytes
|
|
374
|
+
rawSocket.removeAllListeners('data');
|
|
375
|
+
let currentClient = null;
|
|
376
|
+
// Forward provider data to whatever client is currently connected
|
|
377
|
+
rawSocket.on('data', (chunk) => {
|
|
378
|
+
if (currentClient && !currentClient.destroyed) {
|
|
379
|
+
currentClient.write(chunk);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
rawSocket.on('end', () => {
|
|
383
|
+
if (currentClient && !currentClient.destroyed)
|
|
384
|
+
currentClient.end();
|
|
385
|
+
});
|
|
386
|
+
rawSocket.on('error', (err) => {
|
|
387
|
+
warn(`Provider socket error: ${err.message}`);
|
|
388
|
+
if (currentClient && !currentClient.destroyed)
|
|
389
|
+
currentClient.destroy();
|
|
390
|
+
cleanup();
|
|
391
|
+
});
|
|
392
|
+
const server = net.createServer((clientSocket) => {
|
|
393
|
+
if (currentClient && !currentClient.destroyed) {
|
|
394
|
+
// Only one connection at a time — reject new ones
|
|
395
|
+
clientSocket.destroy();
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
currentClient = clientSocket;
|
|
399
|
+
clientSocket.on('data', (chunk) => {
|
|
400
|
+
if (!rawSocket.destroyed)
|
|
401
|
+
rawSocket.write(chunk);
|
|
402
|
+
});
|
|
403
|
+
clientSocket.on('close', () => { currentClient = null; });
|
|
404
|
+
clientSocket.on('error', () => { currentClient = null; });
|
|
405
|
+
});
|
|
406
|
+
server.on('error', (err) => {
|
|
407
|
+
if (!state.httpServer)
|
|
408
|
+
reject(err);
|
|
409
|
+
else
|
|
410
|
+
warn(`TCP proxy error: ${err.message}`);
|
|
411
|
+
});
|
|
412
|
+
server.listen(PORT, () => {
|
|
413
|
+
state.httpServer = server;
|
|
414
|
+
resolve();
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
}
|
|
354
418
|
// --- 4b. WebSocket tunnel (via ws library) ---
|
|
355
419
|
function setupWebSocketProxy(server) {
|
|
356
420
|
const wss = new WebSocketServer({ noServer: true });
|
|
@@ -772,21 +836,43 @@ async function main() {
|
|
|
772
836
|
state.sessionId = ackResp.session_id;
|
|
773
837
|
state.startedAt = Date.now();
|
|
774
838
|
providerPubkey = ackResp.pubkey || null;
|
|
839
|
+
state.isProxyMode = !!ackResp.proxy_mode;
|
|
775
840
|
// If the provider dictated a different rate, use it
|
|
776
841
|
if (ackResp.sats_per_minute && ackResp.sats_per_minute !== satsPerMinute) {
|
|
777
842
|
state.satsPerMinute = ackResp.sats_per_minute;
|
|
778
843
|
log(`Provider adjusted rate: ${ackResp.sats_per_minute} sats/min`);
|
|
779
844
|
}
|
|
780
845
|
log(`Session started: ${state.sessionId}`);
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
try {
|
|
784
|
-
await startHttpProxy();
|
|
785
|
-
log(`Web proxy ready at http://localhost:${PORT}`);
|
|
846
|
+
if (state.isProxyMode) {
|
|
847
|
+
log(`Mode: TCP proxy (one-time fee, raw HTTP passthrough)`);
|
|
786
848
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
849
|
+
else {
|
|
850
|
+
log(`Billing: ${state.satsPerMinute} sats/min via ${paymentMethod}`);
|
|
851
|
+
}
|
|
852
|
+
// 6. Start proxy
|
|
853
|
+
if (state.isProxyMode) {
|
|
854
|
+
// Proxy mode: wait for payment, then switch socket to raw TCP pipe
|
|
855
|
+
const proxyReadyPromise = new Promise(resolve => { state.proxyReady = resolve; });
|
|
856
|
+
log('Waiting for invoice from provider...');
|
|
857
|
+
try {
|
|
858
|
+
await proxyReadyPromise;
|
|
859
|
+
await startTcpProxy();
|
|
860
|
+
log(`TCP proxy ready at http://localhost:${PORT}`);
|
|
861
|
+
}
|
|
862
|
+
catch (e) {
|
|
863
|
+
warn(`Failed to start TCP proxy on port ${PORT}: ${e.message}`);
|
|
864
|
+
warn('Continuing without proxy');
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
try {
|
|
869
|
+
await startHttpProxy();
|
|
870
|
+
log(`Web proxy ready at http://localhost:${PORT}`);
|
|
871
|
+
}
|
|
872
|
+
catch (e) {
|
|
873
|
+
warn(`Failed to start HTTP proxy on port ${PORT}: ${e.message}`);
|
|
874
|
+
warn('Continuing without HTTP proxy');
|
|
875
|
+
}
|
|
790
876
|
}
|
|
791
877
|
// 7. Show ready message and start REPL
|
|
792
878
|
log("Type 'help' for commands");
|
package/dist/swarm.d.ts
CHANGED