Stop starting Unraid's Node CLI on every Partnership render

`unraid-api apikey` costs 1.98s and ran once per render just to answer whether
a key exists. Cached for a minute — still read from the key store, so a
deletion still shows, a minute later rather than instantly. Partner probes are
multiplexed at the same time.
This commit is contained in:
Gmer4Lfe
2026-08-21 08:53:29 -04:00
parent 7c4f881b57
commit 8041da5424
+36 -7
View File
@@ -189,11 +189,24 @@ function vv_pt_ts_peers(): array {
// ── SSH helper — run a single command on a remote host ────────────────────────
// Multiplexed, because this page makes several of these per render — a state read per partner,
// plus whatever a card asks for — and each one was paying a full handshake to a node across a real
// internet hop. Measured at about two seconds per call against 0.09s once a master is up.
//
// The socket lives in tmpfs so a reboot cannot inherit a stale one, and the path is kept short: a
// unix socket path is capped near 108 characters and ssh appends the user and host to this.
function vv_pt_ssh(string $ip, string $sshKey, string $cmd, int $timeout = 4): string {
if (!$ip || !$sshKey || !file_exists($sshKey)) return '';
$sock = rtrim(VV_CACHE_ROOT, '/') . '/ssh';
if (!is_dir($sock)) @mkdir($sock, 0700, true);
$full = sprintf(
'ssh -i %s -o ConnectTimeout=%d -o StrictHostKeyChecking=no -o BatchMode=yes root@%s %s 2>/dev/null',
escapeshellarg($sshKey), $timeout, escapeshellarg($ip), escapeshellarg($cmd)
'ssh -i %s -o ConnectTimeout=%d -o StrictHostKeyChecking=no -o BatchMode=yes'
. ' -o ControlMaster=auto -o ControlPersist=60s -o ControlPath=%s'
. ' root@%s %s 2>/dev/null',
escapeshellarg($sshKey), $timeout, escapeshellarg($sock . '/pt-%h'),
escapeshellarg($ip), escapeshellarg($cmd)
);
return shell_exec($full) ?: '';
}
@@ -513,11 +526,27 @@ function vv_pt_nodes(): array {
$apiKeySet = false;
$apiKeyPreview = '';
if ($isMe) {
$hn = trim((string)shell_exec("hostname -s 2>/dev/null | sed 's/^[Uu][Nn][Rr][Aa][Ii][Dd]-//'")) ?: 'Varaverk';
$keyName = 'Varaverk ' . $hn;
$apiOut = shell_exec('/usr/local/sbin/unraid-api apikey --name ' . escapeshellarg($keyName) . ' --json </dev/null 2>/dev/null');
$apiData = json_decode(trim($apiOut ?? ''), true);
if (is_array($apiData) && !empty($apiData['key'])) {
// Cached for a minute, because `unraid-api apikey` is not a file read — it starts
// Unraid's Node CLI, measured at 1.98s, and it ran on every render of this page. That
// was the single largest cost in assembling it, and this page is the one that opens
// the mesh chat, so it was two seconds in front of a conversation every time.
//
// Still reads the key store rather than the conf, so a key deleted in Unraid's own UI
// is still reflected — a minute later rather than instantly, which is the trade. The
// preview is eight characters of a key that changes when someone deliberately rotates
// it; nobody is watching it to the second.
$apiData = vv_cache_read('pt_apikey', 60);
if ($apiData === null) {
$hn = trim((string)shell_exec("hostname -s 2>/dev/null | sed 's/^[Uu][Nn][Rr][Aa][Ii][Dd]-//'")) ?: 'Varaverk';
$keyName = 'Varaverk ' . $hn;
$apiOut = shell_exec('/usr/local/sbin/unraid-api apikey --name ' . escapeshellarg($keyName) . ' --json </dev/null 2>/dev/null');
$decoded = json_decode(trim($apiOut ?? ''), true);
// Cached either way. A host with no key would otherwise pay the two seconds on
// every render forever, which is the case that needs the cache most.
$apiData = is_array($decoded) ? $decoded : [];
vv_cache_write('pt_apikey', $apiData);
}
if (!empty($apiData['key'])) {
$apiKeySet = true;
$apiKeyPreview = substr($apiData['key'], 0, 8) . '...' . substr($apiData['key'], -4);
}