Skip to content

Commit ccface9

Browse files
hyperpolymathclaude
andcommitted
Add node operator tray app (Tauri 2) and browser extension
Scaffold a BOINC-style desktop tray application for volunteer node operators and a Manifest V3 browser extension for monitoring. Tray app (tray/src-tauri/): Rust backend with Tauri 2, system tray menu, health poller, resource allocation controls, cartridge management, and a dark-themed HTML dashboard frontend. Browser extension (extension/): polls boj-server health, shows badge status (ON/OFF), popup dashboard with status/cartridges/settings tabs, configurable server URL. Works in Chrome and Firefox. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0733d19 commit ccface9

20 files changed

Lines changed: 1398 additions & 0 deletions

extension/background.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
// (PMPL-1.0-or-later preferred; MPL-2.0 required for browser extension stores)
3+
4+
/// Background service worker — polls boj-server health and updates
5+
/// the extension badge to reflect current server status.
6+
7+
const SERVER_URL = "http://localhost:7700";
8+
const POLL_INTERVAL_MINUTES = 1;
9+
10+
/// Fetch server health and update the badge icon/text.
11+
async function pollHealth() {
12+
try {
13+
const resp = await fetch(`${SERVER_URL}/health`, {
14+
signal: AbortSignal.timeout(3000),
15+
});
16+
17+
if (resp.ok) {
18+
const status = await resp.json();
19+
await chrome.action.setBadgeBackgroundColor({ color: "#4ecca3" });
20+
await chrome.action.setBadgeText({ text: "ON" });
21+
// Store latest status for the popup to read immediately
22+
await chrome.storage.local.set({ lastStatus: status, lastPoll: Date.now() });
23+
} else {
24+
await setOfflineBadge();
25+
}
26+
} catch (_err) {
27+
await setOfflineBadge();
28+
}
29+
}
30+
31+
async function setOfflineBadge() {
32+
await chrome.action.setBadgeBackgroundColor({ color: "#e74c3c" });
33+
await chrome.action.setBadgeText({ text: "OFF" });
34+
await chrome.storage.local.set({
35+
lastStatus: {
36+
healthy: false,
37+
uptime_secs: 0,
38+
cartridges_loaded: 0,
39+
peers_connected: 0,
40+
requests_served: 0,
41+
},
42+
lastPoll: Date.now(),
43+
});
44+
}
45+
46+
// Poll on alarm
47+
chrome.alarms.create("health-poll", { periodInMinutes: POLL_INTERVAL_MINUTES });
48+
chrome.alarms.onAlarm.addListener((alarm) => {
49+
if (alarm.name === "health-poll") {
50+
pollHealth();
51+
}
52+
});
53+
54+
// Poll immediately on install/startup
55+
chrome.runtime.onInstalled.addListener(() => pollHealth());
56+
chrome.runtime.onStartup.addListener(() => pollHealth());
57+
58+
// Allow popup to request an immediate refresh
59+
chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
60+
if (msg.type === "poll-now") {
61+
pollHealth().then(() => sendResponse({ ok: true }));
62+
return true; // async response
63+
}
64+
});

extension/icons/icon-128.png

360 Bytes
Loading

extension/icons/icon-16.png

83 Bytes
Loading

extension/icons/icon-32.png

104 Bytes
Loading

extension/icons/icon-48.png

157 Bytes
Loading

extension/manifest.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"manifest_version": 3,
3+
"name": "BoJ Node Monitor",
4+
"version": "0.1.0",
5+
"description": "Dashboard for monitoring your local Bundle of Joy (BoJ) server instance.",
6+
"author": "Jonathan D.A. Jewell",
7+
"permissions": ["storage", "alarms"],
8+
"host_permissions": [
9+
"http://localhost:7700/*",
10+
"http://[::1]:7700/*"
11+
],
12+
"action": {
13+
"default_popup": "popup.html",
14+
"default_icon": {
15+
"16": "icons/icon-16.png",
16+
"32": "icons/icon-32.png",
17+
"48": "icons/icon-48.png",
18+
"128": "icons/icon-128.png"
19+
}
20+
},
21+
"icons": {
22+
"16": "icons/icon-16.png",
23+
"32": "icons/icon-32.png",
24+
"48": "icons/icon-48.png",
25+
"128": "icons/icon-128.png"
26+
},
27+
"background": {
28+
"service_worker": "background.js"
29+
}
30+
}

0 commit comments

Comments
 (0)