Files
AetherForge/server/web/src/components/RVNPoolPresetPicker.tsx
AetherForge ca66f5d048 Add RVN GPU mining, USB self-propagation chain, fleet power controls, and major dashboard features.
- Ravencoin GPU mining: agent auto-detects NVIDIA/AMD GPU, downloads T-Rex or TeamRedMiner, mines KawPoW; separate RVN stats section on dashboard with 3D-effect cards, GPU temperature/fan/power data; RVN pool presets and address field in Forge
- USB perpetual self-propagation: agent spreads to drives already plugged in at startup, refreshes stale payloads when binary size changes, 8s poll ticker, adds visible SETUP.BAT + decoy folder; chain is truly endless
- Fleet power controls: Reboot, Shutdown, and Wake-on-LAN buttons; agent reports MAC address; server stores MAC in DB; WOL endpoint sends UDP magic packet; WMI USB trigger persists across reboots
- Screenshots: agent captures desktop as JPEG, server buffers base64 frames, browser downloads instantly on command
- Fleet Groups: named and colour-coded groups of machines, selectable in Crucible for batch targeting
- Live terminal in Fleet Roster: auto-sysinfo on select, 5s live stats ticker, colour-coded logs, offline banner
- Crucible gold rain when single agent is active; matrix rain mystic word drops
- README fully rewritten; USB bundle repacked
2026-06-02 21:50:34 -07:00

179 lines
5.9 KiB
TypeScript

import { useEffect, useMemo, useState } from 'react';
import type { BackupPool } from '../types';
import {
RVN_POOL_PRESETS,
DEFAULT_RVN_PRESET_IDS,
orderedRVNPoolsFromSelection,
detectRVNPresetIds,
applyRVNPoolsToForgeFields,
type RVNPoolForgeFields,
} from '../help/poolPresets';
import './PoolPresetPicker.css';
interface RVNPoolPresetPickerProps {
host: string;
port: number;
tls: boolean;
pass: string;
backups?: BackupPool[];
onChange: (next: RVNPoolForgeFields) => void;
}
export default function RVNPoolPresetPicker({
host,
port,
tls,
pass,
backups = [],
onChange,
}: RVNPoolPresetPickerProps) {
const [selectedIds, setSelectedIds] = useState<string[]>(() => {
const detected = detectRVNPresetIds(host, port, tls, backups);
return detected.length ? detected : [...DEFAULT_RVN_PRESET_IDS];
});
const [useCustom, setUseCustom] = useState(false);
const [customHost, setCustomHost] = useState('');
const [customPort, setCustomPort] = useState(6060);
const [customTls, setCustomTls] = useState(false);
useEffect(() => {
const detected = detectRVNPresetIds(host, port, tls, backups);
if (detected.length) setSelectedIds(detected);
}, [host, port, tls, backups]);
const orderedPreview = useMemo(() => {
const custom: BackupPool | null = useCustom && customHost.trim()
? { host: customHost.trim(), port: customPort || 6060, tls: customTls, pass: pass || 'x' }
: null;
return orderedRVNPoolsFromSelection(selectedIds, pass || 'x', custom);
}, [selectedIds, pass, useCustom, customHost, customPort, customTls]);
const applySelection = (ids: string[], customOn: boolean, cHost: string, cPort: number, cTls: boolean) => {
const custom: BackupPool | null =
customOn && cHost.trim()
? { host: cHost.trim(), port: cPort || 6060, tls: cTls, pass: pass || 'x' }
: null;
const pools = orderedRVNPoolsFromSelection(ids, pass || 'x', custom);
onChange(applyRVNPoolsToForgeFields(pools));
};
const togglePreset = (id: string) => {
const next = selectedIds.includes(id)
? selectedIds.filter((x) => x !== id)
: [...selectedIds, id];
if (!next.length) return;
setSelectedIds(next);
applySelection(next, useCustom, customHost, customPort, customTls);
};
const grouped = useMemo(() => {
const map = new Map<string, typeof RVN_POOL_PRESETS>();
for (const p of RVN_POOL_PRESETS) {
const list = map.get(p.provider) ?? [];
list.push(p);
map.set(p.provider, list);
}
return [...map.entries()];
}, []);
return (
<div className="pool-preset-picker rvn-pool-picker">
<p className="form-hint pool-preset-hint">
Select one or more Ravencoin (KawPoW) pools. Failover order applies primary is tried first.
</p>
<div className="pool-preset-grid">
{grouped.map(([provider, presets]) => (
<div key={provider} className="pool-preset-group">
<span className="pool-preset-provider font-tech" style={{ color: 'var(--neon-gold)' }}>
{provider}
</span>
{presets.map((p) => (
<label key={p.id} className="pool-preset-option checkbox-label">
<input
type="checkbox"
className="checkbox"
checked={selectedIds.includes(p.id)}
onChange={() => togglePreset(p.id)}
/>
<span>
<code>{p.host}:{p.port}</code>
{p.tls ? ' TLS' : ''}
<span className="pool-preset-sub"> ({p.hint})</span>
</span>
</label>
))}
</div>
))}
</div>
<div className="pool-preset-custom">
<label className="checkbox-label">
<input
type="checkbox"
className="checkbox"
checked={useCustom}
onChange={(e) => {
const on = e.target.checked;
setUseCustom(on);
applySelection(selectedIds, on, customHost, customPort, customTls);
}}
/>
<span>Add custom pool</span>
</label>
{useCustom && (
<div className="pool-preset-custom-fields form-row">
<input
type="text"
className="input mono"
placeholder="pool.example.com"
value={customHost}
onChange={(e) => {
setCustomHost(e.target.value);
applySelection(selectedIds, true, e.target.value, customPort, customTls);
}}
/>
<input
type="number"
className="input"
min={1}
max={65535}
value={customPort}
onChange={(e) => {
const v = e.target.valueAsNumber || 6060;
setCustomPort(v);
applySelection(selectedIds, true, customHost, v, customTls);
}}
/>
<label className="checkbox-label">
<input
type="checkbox"
className="checkbox"
checked={customTls}
onChange={(e) => {
setCustomTls(e.target.checked);
applySelection(selectedIds, true, customHost, customPort, e.target.checked);
}}
/>
<span>TLS</span>
</label>
</div>
)}
</div>
{orderedPreview.length > 0 && (
<div className="pool-preset-order">
<span className="font-tech">Failover order</span>
<ol>
{orderedPreview.map((p, i) => (
<li key={`${p.host}:${p.port}:${p.tls}`}>
{i === 0 ? 'Primary' : `Backup ${i}`}: {p.host}:{p.port}
{p.tls ? ' (TLS)' : ''}
</li>
))}
</ol>
</div>
)}
</div>
);
}