Partnership page: one settings card instead of three, and a Data Transferred card

Windows with runs but no bytes say 'no data moved' rather than 0.00 GB, and rows before the byte-parser fix are excluded rather than summed into a false total.
This commit is contained in:
Gmer4Lfe
2026-08-17 14:36:21 -04:00
parent 49372996ac
commit bce3bf61e9
2 changed files with 160 additions and 20 deletions
+67
View File
@@ -240,6 +240,72 @@ function vv_pt_remote_system(string $ip, string $sshKey): array {
];
}
// ── Transfer volume ───────────────────────────────────────────────────────────
//
// Reads data/db/bandwidth_history.db, one line per completed rsync:
// YYYY-MM-DD|HH:MM|profile|duration|status|bytes
//
// Rows before VV_BW_EPOCH are excluded outright. Until 2026-08-14 rsync.sh read the byte count
// from the wrong field of rsync --stats and every row was written as 0 — 1,423 of them. Summing
// those produces a confident 0.00 GB for any window that reaches back far enough, which is worse
// than an empty card: it is a measurement that looks taken. The cut is on the fix, not on a
// guess about which rows look plausible.
//
// A window whose rows are all zero reports null, not 0, so the UI can say "no transfers
// recorded" rather than assert nothing moved. Those are different claims and only one of them
// is supported by an all-zero column.
define('VV_BW_EPOCH', '2026-08-14');
function vv_pt_transfer_stats(): array {
$file = DATA_DIR . '/db/bandwidth_history.db';
$out = ['epoch' => VV_BW_EPOCH, 'windows' => [], 'live' => null, 'usable_rows' => 0];
$windows = ['24h' => 86400, '7d' => 604800, '30d' => 2592000];
foreach ($windows as $k => $_) $out['windows'][$k] = ['bytes' => null, 'runs' => 0, 'failed' => 0];
if (is_file($file)) {
$now = time();
$epoch = strtotime(VV_BW_EPOCH . ' 00:00:00');
$fh = fopen($file, 'r');
if ($fh) {
while (($line = fgets($fh)) !== false) {
$p = explode('|', trim($line));
if (count($p) < 6) continue;
$ts = strtotime($p[0] . ' ' . $p[1]);
if (!$ts || $ts < $epoch) continue;
$out['usable_rows']++;
$bytes = (int)$p[5];
$failed = ($p[4] ?? '') !== 'success';
foreach ($windows as $k => $span) {
if ($ts < $now - $span) continue;
$w = &$out['windows'][$k];
$w['runs']++;
if ($failed) $w['failed']++;
if ($bytes > 0) $w['bytes'] = (int)$w['bytes'] + $bytes;
unset($w);
}
}
fclose($fh);
}
}
// Live: an rsync this host is running right now. The lock name carries the share, which is
// the only part of "what is moving" worth showing without parsing progress output.
$running = trim((string)shell_exec("pgrep -c -f '^rsync -av' 2>/dev/null")) ;
if ((int)$running > 0) {
$share = '';
foreach (glob('/tmp/unraid_locks/rsync_*.lock') ?: [] as $l) {
$pid = (int)preg_replace('/\D/', '', (string)@file_get_contents($l));
if ($pid && is_dir("/proc/$pid")) {
$share = preg_replace('/^rsync_|\.lock$/', '', basename($l));
break;
}
}
$out['live'] = ['running' => (int)$running, 'share' => $share];
}
return $out;
}
// ── Media seed progress ───────────────────────────────────────────────────────
//
// Phase 3 dispatches Rsync/media_seed.sh detached, because a first seed of a full
@@ -501,6 +567,7 @@ function vv_partnership_all(): array {
'config' => vv_pt_config(),
'nodes' => vv_pt_nodes(),
'sync' => vv_pt_sync(),
'xfer' => vv_pt_transfer_stats(),
'ts' => time(),
];
}