This commit is contained in:
2025-11-15 09:07:04 +01:00
commit d5834de32e
26 changed files with 2170 additions and 0 deletions

36
web/api/cap_reset.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
require __DIR__ . '/../../lib/app.php';
auth_require();
header('Content-Type: application/json');
$stateDir = '/var/lib/snowpanel';
$perFile = $stateDir . '/period.json';
$lockFile = $stateDir . '/cap.lock';
$cfg = app_load_config();
$cap_day = (int)($cfg['cap_day'] ?? 1);
$cap_day = max(1, min(28, $cap_day));
$tz = new DateTimeZone(@date_default_timezone_get() ?: 'UTC');
$now = new DateTime('now', $tz);
$y = (int)$now->format('Y');
$m = (int)$now->format('n');
$d = (int)$now->format('j');
if ($d < $cap_day) {
if ($m === 1) { $m = 12; $y -= 1; } else { $m -= 1; }
}
$anchor = (new DateTime(sprintf('%04d-%02d-%02d 00:00:00', $y, $m, $cap_day), $tz))->getTimestamp();
$period = [
'period_start' => $anchor,
'rx' => 0,
'tx' => 0,
'last_ing' => 0,
'last_egr' => 0,
];
@file_put_contents($perFile, json_encode($period, JSON_UNESCAPED_SLASHES));
@unlink($lockFile);
echo json_encode(['ok' => true]);

54
web/api/limits_get.php Normal file
View File

@@ -0,0 +1,54 @@
<?php
require __DIR__ . '/../lib/app.php';
auth_require();
header('Content-Type: application/json');
$cfg = app_load_config();
$cap_gb = (int)($cfg['cap_gb'] ?? 0);
$cap_reset_day = (int)($cfg['cap_reset_day'] ?? 1);
$rate_mbps = (int)($cfg['rate_mbps'] ?? 0);
$stateDir = '/var/lib/snowpanel';
$statsFile = $stateDir . '/stats.json';
$metaFile = $stateDir . '/meta.json';
$usage = [
'start_ts' => null,
'period_label' => null,
'rx' => 0, 'tx' => 0, 'total' => 0,
'cap_bytes' => $cap_gb > 0 ? $cap_gb * 1024*1024*1024 : 0,
'cap_hit' => false,
];
if (is_file($metaFile)) {
$m = json_decode((string)file_get_contents($metaFile), true);
if (is_array($m)) {
foreach (['start_ts','period_label','rx','tx','total','cap_bytes','cap_hit'] as $k) {
if (array_key_exists($k, $m)) $usage[$k] = $m[$k];
}
}
}
$current_rate_mbps = 0.0;
if (is_file($statsFile)) {
$s = json_decode((string)file_get_contents($statsFile), true);
$arr = is_array($s) ? ($s['data'] ?? []) : [];
$n = count($arr);
if ($n >= 2) {
$a = $arr[$n-2]; $b = $arr[$n-1];
$dt = max(1, (int)$b['t'] - (int)$a['t']);
$dr = max(0, (int)$b['read'] - (int)$a['read']);
$dw = max(0, (int)$b['written'] - (int)$a['written']);
$current_rate_mbps = (($dr + $dw) * 8.0) / $dt / 1_000_000.0;
}
}
echo json_encode([
'ok' => true,
'cap_gb' => $cap_gb,
'cap_reset_day' => $cap_reset_day,
'rate_mbps' => $rate_mbps,
'usage' => $usage,
'current_rate_mbps' => $current_rate_mbps
]);

28
web/api/limits_set.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
require __DIR__ . '/../lib/app.php';
auth_require();
header('Content-Type: application/json; charset=utf-8');
$raw = file_get_contents('php://input');
$in = json_decode((string)$raw, true);
if (!is_array($in)) {
echo json_encode(['ok' => false, 'error' => 'bad json']);
exit;
}
$cap_gb = max(0, (int)($in['cap_gb'] ?? 0));
$cap_reset_day = min(28, max(1, (int)($in['cap_reset_day'] ?? 1)));
$rate_mbps = max(0, (int)($in['rate_mbps'] ?? 0));
$cfg = app_load_config();
$cfg['cap_gb'] = $cap_gb;
$cfg['cap_reset_day'] = $cap_reset_day;
$cfg['rate_mbps'] = $rate_mbps;
if (!app_save_config($cfg)) {
echo json_encode(['ok' => false, 'error' => 'save failed']);
exit;
}
echo json_encode(['ok' => true]);

23
web/api/snow_log.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
require __DIR__ . '/../lib/app.php';
header('Content-Type: application/json');
@ini_set('display_errors','0');
@error_reporting(0);
$n = isset($_GET['n']) ? (int)$_GET['n'] : 500;
if ($n < 1) $n = 200;
if ($n > 5000) $n = 5000;
$l = $_GET['level'] ?? 'info';
$levels = ['debug','info','notice','warning','err'];
$level = in_array($l,$levels,true) ? $l : 'info';
$out = [];
$rc = 0;
$cmd = '/usr/bin/sudo /usr/local/bin/snowpanel-logdump ' . escapeshellarg((string)$n) . ' ' . escapeshellarg($level) . ' 2>&1';
@exec($cmd, $out, $rc);
$lines = array_values(array_filter($out, static function($x){ return trim($x) !== ''; }));
echo json_encode(['ok'=>!empty($lines), 'lines'=>$lines], JSON_UNESCAPED_SLASHES);

5
web/api/snow_status.php Normal file
View File

@@ -0,0 +1,5 @@
<?php
require __DIR__ . '/../lib/app.php'; auth_require();
require __DIR__ . '/../lib/snowctl.php';
header('Content-Type: application/json');
echo json_encode(snowctl_status());

33
web/api/stats.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
require __DIR__ . '/../lib/app.php';
header('Content-Type: application/json; charset=utf-8');
$rows=[];
$state='/var/lib/snowpanel/stats.json';
if (is_file($state)) {
$j=json_decode((string)@file_get_contents($state),true);
if (is_array($j) && isset($j['data']) && is_array($j['data'])) $rows=$j['data'];
}
if (count($rows)<2) {
$lines=[];
$out=@shell_exec('sudo /usr/local/bin/snowpanel-logdump 20000 info 2>/dev/null');
if (is_string($out) && $out!=='') $lines=preg_split('/\r?\n/',trim($out));
else @exec('journalctl -u snowflake-proxy --since "48 hours ago" -o short-iso --no-pager 2>/dev/null',$lines);
$cum_rx=0; $cum_tx=0; $tmp=[];
foreach($lines as $line){
if(!preg_match('~^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[+\-]\d{2}:\d{2})?).*Traffic\s+Relayed.*?([0-9]+)\s*KB\s*,\s*([0-9]+)\s*KB~i',$line,$m)) continue;
$ts=strtotime($m[1]); if($ts===false) continue;
$tx_kb=(int)$m[2]; $rx_kb=(int)$m[3];
$cum_rx+=$rx_kb*1024; $cum_tx+=$tx_kb*1024;
$tmp[]=['t'=>$ts,'read'=>$cum_rx,'written'=>$cum_tx];
}
if(!empty($tmp)) $rows=$tmp;
}
usort($rows,function($a,$b){return $a['t']<=>$b['t'];});
if(count($rows)===1){
$d0=$rows[0];
array_unshift($rows,['t'=>$d0['t']-60,'read'=>$d0['read'],'written'=>$d0['written']]);
}
$cut=time()-172800;
$rows=array_values(array_filter($rows,function($r)use($cut){return (int)$r['t']>=$cut;}));
echo json_encode(['ok'=>true,'data'=>$rows],JSON_UNESCAPED_SLASHES);