posimai-station-app/main.js

96 lines
3.5 KiB
JavaScript
Raw Permalink Normal View History

'use strict';
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const os = require('os');
const { execSync } = require('child_process');
// ── ウィンドウ作成 ──────────────────────────────────────────────
function createWindow() {
const win = new BrowserWindow({
width: 1920,
height: 1080,
fullscreen: process.env.KIOSK === '1', // KIOSK=1 で全画面起動
backgroundColor: '#0C1221',
autoHideMenuBar: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true, // セキュリティ必須
nodeIntegration: false, // セキュリティ必須
},
});
// Design Bバイナリ雨オーロラ背景をメインとして起動
// Design A に切り替えたい場合: DESIGN=a npm start
const design = process.env.DESIGN === 'a' ? 'station.html' : 'station-b.html';
win.loadFile(path.join(__dirname, 'renderer', design));
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });
// ── CPU サンプリング100ms 2回測定 ──────────────────────────
function getCpuSample() {
return os.cpus().map(c => {
const total = Object.values(c.times).reduce((a, b) => a + b, 0);
return { total, idle: c.times.idle };
});
}
// ── システムメトリクス取得 IPC ─────────────────────────────────
ipcMain.handle('get-metrics', async () => {
const s1 = getCpuSample();
await new Promise(r => setTimeout(r, 100));
const s2 = getCpuSample();
const cpuPct = s1.reduce((sum, c1, i) => {
const c2 = s2[i];
const dIdle = c2.idle - c1.idle;
const dTotal = c2.total - c1.total;
return sum + (dTotal > 0 ? (1 - dIdle / dTotal) * 100 : 0);
}, 0) / s1.length;
const mem = os.freemem();
const total = os.totalmem();
let disk = null;
try {
const dfOut = execSync('df -B1 / 2>/dev/null', { timeout: 2000 }).toString();
const parts = dfOut.trim().split('\n')[1].split(/\s+/);
disk = {
total_gb: Math.round(parseInt(parts[1]) / 1e9 * 10) / 10,
used_gb: Math.round(parseInt(parts[2]) / 1e9 * 10) / 10,
use_pct: Math.round(parseInt(parts[2]) / parseInt(parts[1]) * 100),
};
} catch (_) {}
return {
ok: true,
hostname: os.hostname(),
uptime_s: Math.floor(os.uptime()),
cpu_pct: Math.round(cpuPct),
cpu_count: os.cpus().length,
load_avg: os.loadavg().map(l => Math.round(l * 100) / 100),
mem_used_mb: Math.round((total - mem) / 1024 / 1024),
mem_total_mb: Math.round(total / 1024 / 1024),
disk,
active_sessions: 0,
node_version: process.version,
platform: os.platform(),
timestamp: new Date().toISOString(),
};
});
// ── サービス死活チェック IPC ───────────────────────────────────
ipcMain.handle('check-service', async (_event, url) => {
const t0 = Date.now();
try {
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), 5000);
const r = await fetch(url, { method: 'HEAD', signal: ctrl.signal });
clearTimeout(timer);
return { ok: true, status: r.status, latency_ms: Date.now() - t0 };
} catch (e) {
return { ok: false, error: e.message, latency_ms: Date.now() - t0 };
}
});