@balaji003/lantransfer 1.0.3 → 1.0.5
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/package.json +1 -1
- package/server.js +83 -43
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -165,6 +165,20 @@ const server = http.createServer(async (req, res) => {
|
|
|
165
165
|
return;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
// ── Ping endpoint for HTTP-based discovery ──
|
|
169
|
+
if (req.method === 'GET' && req.url === '/api/ping') {
|
|
170
|
+
res.writeHead(200, {
|
|
171
|
+
'Content-Type': 'application/json',
|
|
172
|
+
'Access-Control-Allow-Origin': '*',
|
|
173
|
+
});
|
|
174
|
+
res.end(JSON.stringify({
|
|
175
|
+
app: 'lantransfer',
|
|
176
|
+
device_name: deviceName,
|
|
177
|
+
tcp_port: TRANSFER_PORT,
|
|
178
|
+
}));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
168
182
|
// ── SSE stream ──
|
|
169
183
|
if (req.method === 'GET' && req.url === '/events') {
|
|
170
184
|
res.writeHead(200, {
|
|
@@ -504,54 +518,83 @@ function formatSize(bytes) {
|
|
|
504
518
|
}
|
|
505
519
|
|
|
506
520
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
507
|
-
//
|
|
521
|
+
// HTTP-based discovery (no firewall rules needed — outbound TCP only)
|
|
508
522
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
509
|
-
function
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
523
|
+
function getSubnetIPs() {
|
|
524
|
+
const results = [];
|
|
525
|
+
for (const ifaces of Object.values(os.networkInterfaces())) {
|
|
526
|
+
for (const iface of ifaces) {
|
|
527
|
+
if (iface.family === 'IPv4' && !iface.internal && iface.netmask) {
|
|
528
|
+
const ipParts = iface.address.split('.').map(Number);
|
|
529
|
+
const maskParts = iface.netmask.split('.').map(Number);
|
|
530
|
+
// Only scan /24 or smaller subnets to keep it fast
|
|
531
|
+
if (maskParts[2] === 255) {
|
|
532
|
+
const base = ipParts.slice(0, 3).join('.');
|
|
533
|
+
for (let i = 1; i < 255; i++) {
|
|
534
|
+
const ip = `${base}.${i}`;
|
|
535
|
+
if (ip !== iface.address) results.push(ip);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
522
538
|
}
|
|
523
539
|
}
|
|
540
|
+
}
|
|
541
|
+
return results;
|
|
542
|
+
}
|
|
524
543
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const psCmd = `powershell -Command "Start-Process cmd -ArgumentList '/c ${addCmd.replace(/"/g, '\\"')}' -Verb RunAs -Wait"`;
|
|
539
|
-
|
|
540
|
-
exec(psCmd, { windowsHide: false, timeout: 60_000 }, (err2) => {
|
|
541
|
-
if (err2) {
|
|
542
|
-
console.log(' !! Could not add firewall rule. Discovery may not work.');
|
|
543
|
-
console.log(' !! To fix manually:');
|
|
544
|
-
console.log(' !! 1. Open Windows Security > Firewall & network protection');
|
|
545
|
-
console.log(' !! 2. Click "Allow an app through firewall"');
|
|
546
|
-
console.log(' !! 3. Add Node.js and allow Private + Public networks');
|
|
547
|
-
console.log('');
|
|
548
|
-
} else {
|
|
549
|
-
console.log(' Firewall: Rule added successfully! Discovery should work now.');
|
|
550
|
-
}
|
|
544
|
+
function pingHost(ip) {
|
|
545
|
+
return new Promise(resolve => {
|
|
546
|
+
const req = http.get(`http://${ip}:${HTTP_PORT}/api/ping`, { timeout: 800 }, res => {
|
|
547
|
+
let body = '';
|
|
548
|
+
res.on('data', c => body += c);
|
|
549
|
+
res.on('end', () => {
|
|
550
|
+
try {
|
|
551
|
+
const d = JSON.parse(body);
|
|
552
|
+
if (d.app === 'lantransfer' && d.device_name !== deviceName) {
|
|
553
|
+
resolve({ ip, device_name: d.device_name, tcp_port: d.tcp_port });
|
|
554
|
+
} else resolve(null);
|
|
555
|
+
} catch { resolve(null); }
|
|
556
|
+
});
|
|
551
557
|
});
|
|
558
|
+
req.on('error', () => resolve(null));
|
|
559
|
+
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
552
560
|
});
|
|
553
561
|
}
|
|
554
562
|
|
|
563
|
+
let httpScanning = false;
|
|
564
|
+
async function httpDiscoveryScan() {
|
|
565
|
+
if (!isDiscoverable || httpScanning) return;
|
|
566
|
+
httpScanning = true;
|
|
567
|
+
try {
|
|
568
|
+
const ips = getSubnetIPs();
|
|
569
|
+
// Scan in batches of 50 to avoid fd exhaustion
|
|
570
|
+
for (let i = 0; i < ips.length; i += 50) {
|
|
571
|
+
const batch = ips.slice(i, i + 50);
|
|
572
|
+
const results = await Promise.all(batch.map(pingHost));
|
|
573
|
+
for (const r of results) {
|
|
574
|
+
if (!r) continue;
|
|
575
|
+
const id = `${r.ip}:${r.tcp_port}`;
|
|
576
|
+
const isNew = !peers.has(id);
|
|
577
|
+
peers.set(id, {
|
|
578
|
+
device_name: r.device_name,
|
|
579
|
+
ip: r.ip,
|
|
580
|
+
tcp_port: r.tcp_port,
|
|
581
|
+
last_seen: Date.now(),
|
|
582
|
+
});
|
|
583
|
+
if (isNew) {
|
|
584
|
+
console.log(` Found: ${r.device_name} (${r.ip})`);
|
|
585
|
+
broadcast();
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
} catch { /* scan error, ignore */ }
|
|
590
|
+
httpScanning = false;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Run HTTP discovery scan every 5 seconds
|
|
594
|
+
setInterval(httpDiscoveryScan, 5_000);
|
|
595
|
+
// Also run immediately on start (after a short delay for server to be ready)
|
|
596
|
+
setTimeout(httpDiscoveryScan, 1_000);
|
|
597
|
+
|
|
555
598
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
556
599
|
// Start
|
|
557
600
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
@@ -572,9 +615,6 @@ server.listen(HTTP_PORT, () => {
|
|
|
572
615
|
console.log(` UI: http://localhost:${HTTP_PORT}`);
|
|
573
616
|
console.log('');
|
|
574
617
|
|
|
575
|
-
// Check firewall on Windows
|
|
576
|
-
checkWindowsFirewall();
|
|
577
|
-
|
|
578
618
|
// Auto-open browser
|
|
579
619
|
const url = `http://localhost:${HTTP_PORT}`;
|
|
580
620
|
if (process.platform === 'win32') exec(`start "" "${url}"`);
|