Rename to hkt.sh
This commit is contained in:
141
projects/dstatus/dstatus-mac-agent.js
Normal file
141
projects/dstatus/dstatus-mac-agent.js
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* DStatus macOS Agent - Mac mini M2
|
||||
* 模拟 Go agent 上报格式: POST /stats/update, Header Key, Body {sid, data}
|
||||
*/
|
||||
const os = require('os');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const CONFIG = {
|
||||
server: 'http://51.81.222.43:5555',
|
||||
apiKey: 'macmini_report_key_2026',
|
||||
sid: '3b24c3cb-d06b-4747-83a8-a4c1ca11d4df',
|
||||
interval: 2,
|
||||
device: 'en0'
|
||||
};
|
||||
|
||||
let prevRx = 0, prevTx = 0, prevTime = 0, firstRx = 0, firstTx = 0;
|
||||
|
||||
function getCpu() {
|
||||
try {
|
||||
const out = execSync("ps -A -o %cpu | awk '{s+=$1} END {print s/100}'", { encoding: 'utf8', timeout: 3000 });
|
||||
const v = parseFloat(out.trim()) || 0;
|
||||
return { multi: Math.min(v, 1), single: os.cpus().map(() => Math.min(v, 1)) };
|
||||
} catch { return { multi: 0, single: [0] }; }
|
||||
}
|
||||
|
||||
function getDisk() {
|
||||
try {
|
||||
const out = execSync("df -k / | tail -1", { encoding: 'utf8', timeout: 3000 });
|
||||
const p = out.trim().split(/\s+/);
|
||||
const total = parseInt(p[1]) * 1024;
|
||||
const used = parseInt(p[2]) * 1024;
|
||||
const free = parseInt(p[3]) * 1024;
|
||||
const pct = parseFloat(p[4]) || 0;
|
||||
return {
|
||||
free, total, used,
|
||||
disks: [{ device: p[0], free, total, used, fstype: 'apfs', mount: '/', percent: pct }]
|
||||
};
|
||||
} catch { return { free: 0, total: 0, used: 0, disks: [] }; }
|
||||
}
|
||||
|
||||
function getMem() {
|
||||
const total = os.totalmem();
|
||||
const free = os.freemem();
|
||||
const used = total - free;
|
||||
return {
|
||||
virtual: {
|
||||
total, available: free, used, usedPercent: (used / total) * 100,
|
||||
free, active: 0, inactive: 0, wired: 0, laundry: 0,
|
||||
buffers: 0, cached: 0, writeBack: 0, dirty: 0,
|
||||
writeBackTmp: 0, shared: 0, slab: 0, sreclaimable: 0,
|
||||
sunreclaim: 0, pageTables: 0, swapCached: 0,
|
||||
commitLimit: 0, committedAS: 0, highTotal: 0, highFree: 0,
|
||||
lowTotal: 0, lowFree: 0, swapTotal: 0, swapFree: 0,
|
||||
mapped: 0, vmallocTotal: 0, vmallocUsed: 0, vmallocChunk: 0,
|
||||
hugePagesTotal: 0, hugePagesFree: 0, hugePagesRsvd: 0,
|
||||
hugePagesSurp: 0, hugePageSize: 0, anonHugePages: 0
|
||||
},
|
||||
swap: { total: 0, used: 0, free: 0, usedPercent: 0, sin: 0, sout: 0, pgIn: 0, pgOut: 0, pgFault: 0, pgMajFault: 0 }
|
||||
};
|
||||
}
|
||||
|
||||
function getNet() {
|
||||
try {
|
||||
const out = execSync(`netstat -ibI ${CONFIG.device} | awk 'NR==2{print $7,$10}'`, { encoding: 'utf8', timeout: 3000 });
|
||||
const [rx, tx] = out.trim().split(/\s+/).map(Number);
|
||||
const now = Date.now();
|
||||
if (!firstRx) { firstRx = rx; firstTx = tx; }
|
||||
const deltaIn = prevRx ? Math.max(0, (rx || 0) - prevRx) : 0;
|
||||
const deltaOut = prevTx ? Math.max(0, (tx || 0) - prevTx) : 0;
|
||||
prevRx = rx || 0; prevTx = tx || 0; prevTime = now;
|
||||
return {
|
||||
delta: { in: deltaIn, out: deltaOut },
|
||||
total: { in: (rx || 0) - firstRx, out: (tx || 0) - firstTx }
|
||||
};
|
||||
} catch { return { delta: { in: 0, out: 0 }, total: { in: 0, out: 0 } }; }
|
||||
}
|
||||
|
||||
function getHost() {
|
||||
return {
|
||||
hostname: os.hostname(),
|
||||
uptime: Math.floor(os.uptime()),
|
||||
bootTime: Math.floor(Date.now() / 1000 - os.uptime()),
|
||||
procs: 0,
|
||||
os: 'darwin',
|
||||
platform: 'macOS',
|
||||
platformFamily: 'darwin',
|
||||
platformVersion: os.release(),
|
||||
kernelVersion: os.release(),
|
||||
kernelArch: os.arch() === 'arm64' ? 'aarch64' : os.arch(),
|
||||
virtualizationSystem: '',
|
||||
virtualizationRole: '',
|
||||
hostId: CONFIG.sid
|
||||
};
|
||||
}
|
||||
|
||||
function collectData() {
|
||||
const cpu = getCpu();
|
||||
const disk = getDisk();
|
||||
const mem = getMem();
|
||||
const net = getNet();
|
||||
const host = getHost();
|
||||
return {
|
||||
cpu, disk: { free: disk.free, total: disk.total, used: disk.used },
|
||||
disks: disk.disks, host, hostname: os.hostname(),
|
||||
mem, net, timestamp: Date.now()
|
||||
};
|
||||
}
|
||||
|
||||
function report() {
|
||||
const data = collectData();
|
||||
const body = JSON.stringify({ sid: CONFIG.sid, data });
|
||||
const mod = CONFIG.server.startsWith('https') ? https : http;
|
||||
const req = mod.request(`${CONFIG.server}/stats/update`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(body),
|
||||
'Key': CONFIG.apiKey
|
||||
}
|
||||
}, res => {
|
||||
let d = '';
|
||||
res.on('data', c => d += c);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const r = JSON.parse(d);
|
||||
if (r.success || r.status === 1) console.log(`[${new Date().toLocaleTimeString()}] ✅ 上报成功`);
|
||||
else console.log(`[${new Date().toLocaleTimeString()}] ❌`, d.substring(0, 100));
|
||||
} catch { console.log(`[${new Date().toLocaleTimeString()}] ❌ 解析失败:`, d.substring(0, 100)); }
|
||||
});
|
||||
});
|
||||
req.on('error', e => console.error('上报错误:', e.message));
|
||||
req.write(body);
|
||||
req.end();
|
||||
}
|
||||
|
||||
console.log('DStatus macOS Agent | SID:', CONFIG.sid);
|
||||
report();
|
||||
setInterval(report, CONFIG.interval * 1000);
|
||||
Reference in New Issue
Block a user