-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnode_heartbeat.js
More file actions
112 lines (92 loc) · 3.03 KB
/
node_heartbeat.js
File metadata and controls
112 lines (92 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import "dotenv/config";
import { ethers } from "ethers";
import crypto from "crypto";
const API_URL = process.env.API_URL || "http://localhost:8080";
const HEARTBEAT_URL = `${API_URL}/heartbeat`;
const PAIR_URL = `${API_URL}/pair/confirm`;
const NODE_PRIVATE_KEY = process.env.NODE_PRIVATE_KEY;
if (!NODE_PRIVATE_KEY) {
console.error("Missing NODE_PRIVATE_KEY in .env");
process.exit(1);
}
const wallet = new ethers.Wallet(NODE_PRIVATE_KEY);
// Simple CLI args
const args = process.argv.slice(2);
const pairingCode = args.find(a => a.startsWith('--code='))?.split('=')[1] || args[args.indexOf('--code') + 1];
function heartbeatMessage({ timestamp }) {
// Server expects: "HEARTBEAT:{timestamp}" (Phase 3 in server.js)
return `HEARTBEAT:${timestamp}`;
}
async function pairWithCode(code) {
const nodeWallet = await wallet.getAddress();
console.log(`[PAIRING] Attempting to pair with code: ${code}...`);
try {
const res = await fetch(PAIR_URL, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
code: code,
device_id: nodeWallet
})
});
const out = await res.json();
if (out.ok) {
console.log("[PAIRING] SUCCESS!");
} else {
console.error("[PAIRING] FAILED:", out.error);
}
return out;
} catch (e) {
console.error("[PAIRING] ERROR:", e.message);
return { ok: false };
}
}
async function sendHeartbeat(stats = null) {
const nodeWallet = await wallet.getAddress();
const timestamp = Date.now(); // server.js expects Date.now() in ms, then checks drift
// Realistic simulated stats: 15–80ms latency, 20–150 MB per direction
const MB = 1024 * 1024;
const rand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
const heartbeatStats = stats || {
latencyMs: rand(15, 80),
bytesUp: rand(20, 150) * MB,
bytesDown: rand(30, 150) * MB,
};
const msg = heartbeatMessage({ timestamp });
const signature = await wallet.signMessage(msg);
// server.js expects { node_id, wallet, timestamp, signature }
const payload = {
node_id: nodeWallet,
wallet: nodeWallet,
timestamp,
stats: heartbeatStats,
signature
};
try {
const res = await fetch(HEARTBEAT_URL, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(payload),
});
const out = await res.json().catch(() => ({}));
console.log(new Date().toISOString(), "heartbeat:", res.status, out);
return out;
} catch (e) {
console.error("Heartbeat Send Error:", e.message);
}
}
async function runE2E() {
console.log("Satelink Node Agent Simulator");
const nodeWallet = await wallet.getAddress();
console.log("Wallet:", nodeWallet);
if (pairingCode) {
await pairWithCode(pairingCode);
} else {
console.log("No pairing code provided, skipping pairing step...");
}
console.log("Sending initial heartbeat...");
await sendHeartbeat();
console.log("Entering heartbeat loop (60s)...");
setInterval(sendHeartbeat, 60_000);
}
runE2E();