ui-mock replays a captured machine's state and chain feed (IGNEUM_MOCK_STATE, IGNEUM_MOCK_LIVE); the fleet watts count mining and tuning cards only; PC 2's 0.3.16 state rendered in light and dark
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
6dd3c3686b
commit
24adda1025
6 changed files with 18 additions and 4 deletions
|
|
@ -344,8 +344,9 @@ var View = (function () {
|
|||
// MH per watt: the engine's live figure, else rate over draw
|
||||
function effOf(cd) { if (cd.eff_mhw > 0) return cd.eff_mhw; return cd.power_w > 0 && cd.hash_now > 0 ? cd.hash_now / cd.power_w : 0; }
|
||||
function effText(e) { return e > 0 ? (e >= 10 ? e.toFixed(1) : e.toFixed(2)) + ' MH/W' : ''; }
|
||||
// the watts drawn now by the present cards
|
||||
function wattsTotal(cards) { return (cards || []).filter(present).reduce(function (a, c) { return a + (c.power_w > 0 ? c.power_w : 0); }, 0); }
|
||||
// the watts drawn now by the cards that are mining or tuning (an idle card's standby draw is not the fleet's cost;
|
||||
// the 0.3.17 engine's mining.watts_total counts the same way)
|
||||
function wattsTotal(cards) { return (cards || []).filter(function (c) { return present(c) && (c.state === 'mining' || c.state === 'tuning'); }).reduce(function (a, c) { return a + (c.power_w > 0 ? c.power_w : 0); }, 0); }
|
||||
// why a row has no power or temperature cell: one sentence, once, instead of three n/a
|
||||
function noReading(cd) {
|
||||
if (cd.power_w > 0 || cd.temp_gpu > 0) return '';
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ test('money: £ a day from watts at a price, nothing without one, the cells leav
|
|||
assert.equal(apple.noReading, 'No power or temperature reading on Apple silicon');
|
||||
assert.equal(V.cells(card({ kind: 'integrated', vendor: 'other', power_w: 0, temp_gpu: 0, eff_mhw: 0 }), 28).noReading, 'No power or temperature reading on an integrated GPU');
|
||||
assert.equal(V.wattsTotal([card(), card({ key: 'b', power_w: 100 }), card({ key: 'c', power_w: 50, removed_at: 5 })]), 510.2);
|
||||
assert.equal(V.wattsTotal([card(), card({ key: 'd', power_w: 48, state: 'off', enabled: false })]), 410.2, 'an idle card’s standby draw is not counted');
|
||||
assert.equal(V.effText(V.effOf(card({ eff_mhw: 0.422 }))), '0.42 MH/W');
|
||||
assert.equal(V.effText(V.effOf(card({ eff_mhw: 0, power_w: 0 }))), '');
|
||||
});
|
||||
|
|
|
|||
BIN
docs/plans/miner-ui-4/pc2-0.3.16/pc2-cards-light-1440.png
Normal file
BIN
docs/plans/miner-ui-4/pc2-0.3.16/pc2-cards-light-1440.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 261 KiB |
BIN
docs/plans/miner-ui-4/pc2-0.3.16/pc2-overview-dark-1440.png
Normal file
BIN
docs/plans/miner-ui-4/pc2-0.3.16/pc2-overview-dark-1440.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 398 KiB |
BIN
docs/plans/miner-ui-4/pc2-0.3.16/pc2-overview-light-1440.png
Normal file
BIN
docs/plans/miner-ui-4/pc2-0.3.16/pc2-overview-light-1440.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 406 KiB |
|
|
@ -31,7 +31,10 @@ const coin = path.resolve(here, '../../brand/igneum-coin-1024.png');
|
|||
const port = parseInt(process.argv[2] || '4310', 10);
|
||||
const PREFIX = '/t/mock';
|
||||
|
||||
const recState = JSON.parse(fs.readFileSync(path.join(here, 'recorded/state.json'), 'utf8'));
|
||||
// IGNEUM_MOCK_STATE=<file> replays a state captured from a real machine (relay/playbooks/app-state-grab.ps1) instead of
|
||||
// the recorded one; IGNEUM_MOCK_LIVE=<file> serves that machine's /api/live reply as it was (timestamps shifted to now)
|
||||
const recState = JSON.parse(fs.readFileSync(process.env.IGNEUM_MOCK_STATE || path.join(here, 'recorded/state.json'), 'utf8'));
|
||||
const recLive = process.env.IGNEUM_MOCK_LIVE ? JSON.parse(fs.readFileSync(process.env.IGNEUM_MOCK_LIVE, 'utf8')) : null;
|
||||
const recLog = JSON.parse(fs.readFileSync(path.join(here, 'recorded/log.json'), 'utf8')).lines;
|
||||
const t0 = Date.now() / 1000; // server start
|
||||
const shift = t0 - recState.now; // recorded clock -> live clock
|
||||
|
|
@ -116,6 +119,8 @@ function stateNow() {
|
|||
s.program.eta_s = Math.max(0, Math.round(3600 - ((t - t0) % 3600)));
|
||||
s.node.blocks = recState.node.blocks + Math.floor(t - t0); s.node.headers = s.node.blocks; s.node.daa = s.node.blocks;
|
||||
s.node.last_reading_age_s = (t - t0) % 10;
|
||||
// a captured state (IGNEUM_MOCK_STATE) is replayed as it was: the machine's own name, cards, rate and numbers
|
||||
if (process.env.IGNEUM_MOCK_STATE) { s.node.blocks = recState.node.blocks; s.node.headers = recState.node.headers; s.node.daa = recState.node.daa; return s; }
|
||||
// a live-looking hash rate
|
||||
const wob = Math.sin((t - t0) / 7) * 1.4;
|
||||
s.mining.hash_total = +(16.9 + wob).toFixed(2); s.mining.cards[0].hash_now = s.mining.hash_total;
|
||||
|
|
@ -180,7 +185,14 @@ http.createServer((req, res) => {
|
|||
return send(res, 200, types['.html'], fs.readFileSync(path.join(uiDir, 'index.html')));
|
||||
}
|
||||
if (rest === '/api/state' && req.method === 'GET') return json(res, stateNow());
|
||||
if (rest === '/api/live' && req.method === 'GET') return json(res, liveNow(parseInt(u.searchParams.get('window') || '120', 10)));
|
||||
if (rest === '/api/live' && req.method === 'GET') {
|
||||
if (recLive && recLive.blocks) {
|
||||
// replayed with its newest block 3 s behind now, so the module's window shows it as it was captured
|
||||
const newest = Math.max(...recLive.blocks.map(b => b.ts || 0)), dt = Date.now() - 3000 - newest;
|
||||
const d = JSON.parse(JSON.stringify(recLive)); d.blocks.forEach(b => { b.ts = (b.ts || newest) + dt; if (!b.miner) b.miner = 'unknown'; }); d.now = Math.floor(Date.now() / 1000); return json(res, d);
|
||||
}
|
||||
return json(res, liveNow(parseInt(u.searchParams.get('window') || '120', 10)));
|
||||
}
|
||||
if (rest === '/api/log' && req.method === 'GET') {
|
||||
const after = parseInt(u.searchParams.get('after') || '0', 10), limit = Math.min(20000, parseInt(u.searchParams.get('limit') || '400', 10));
|
||||
let out = log.filter(l => l.seq > after); if (out.length > limit) out = out.slice(out.length - limit);
|
||||
|
|
|
|||
Loading…
Reference in a new issue