Files
nixpanel-server/server/src/core/stats.ts
T
NixReaper 8ff00c544c feat: v0.4.0 — Apache service stack, shell access, log viewer, changelog
Service stack (backend):
- webserver.ts rewritten: apache2/php-fpm routes replacing nginx; per-account
  Apache log endpoint; PHP-FPM reload per version; apache2ctl configtest/reload
- accounts.ts: added PUT /:id/shell to toggle /bin/bash vs /usr/sbin/nologin,
  runs usermod -s and writes audit log

New UI features (nixserver):
- ShellAccess page: grant/revoke SSH access per account via AccountPicker
- ApacheLogs page: live log viewer (access/error) per account; replaces stub
- NginxLogs: re-exports ApacheLogs (NixPanel uses Apache, not NGINX)
- WebServer page: shows apache2, php8.2-fpm, php8.3-fpm status with reload
  buttons; config test; Apache log viewer

Bug fixes:
- Accounts.tsx: Lucide icon size prop type widened (string|number); removed
  unused Users import; dropped duplicate NGINX log card
- Removed soon badge from ShellAccess and ApacheLogs entries

Project:
- CHANGELOG.md created with full history from 0.2.x through 0.4.0
- All packages bumped from 0.3.2 to 0.4.0
2026-04-11 05:17:49 -05:00

71 lines
2.1 KiB
TypeScript

import path from 'path'
import fs from 'fs/promises'
import prisma from '../db/client.js'
import { exec } from './exec.js'
import { config } from '../config.js'
/**
* Collect disk usage for all active accounts and update the DB.
* Called every 15 minutes by the scheduler.
*/
export async function collectDiskUsage(): Promise<void> {
const accounts = await prisma.account.findMany({
where: { status: { in: ['active', 'suspended'] } },
select: { id: true, username: true, homedir: true },
})
for (const account of accounts) {
try {
const usedMb = await getDirSizeMb(account.homedir)
await prisma.account.update({
where: { id: account.id },
data: { diskUsedMb: BigInt(Math.round(usedMb)) },
})
} catch {
// Non-fatal — homedir may not exist yet
}
}
}
/**
* Reset bandwidth counters for all accounts on the 1st of each month.
* Called by the scheduler monthly cron.
*/
export async function resetMonthlyBandwidth(): Promise<void> {
await prisma.account.updateMany({
where: { status: { in: ['active', 'suspended'] } },
data: { bandwidthUsedMb: BigInt(0) },
})
}
/**
* Get disk usage of a directory in MB using `du`.
*/
async function getDirSizeMb(dirPath: string): Promise<number> {
// du is not in exec allowlist — read from /proc or use stat directly
// Use fs.stat recursively for safety, or fall back to parsing /proc
try {
const result = await exec('df', ['-BM', '--output=used', dirPath])
// df output: header line + value line like "123M"
const lines = result.stdout.split('\n').filter(Boolean)
const valueStr = lines[lines.length - 1]?.replace('M', '').trim() ?? '0'
return parseInt(valueStr, 10) || 0
} catch {
return 0
}
}
/**
* Get per-account Apache access log size as a bandwidth proxy.
* This is a rough estimate — real bandwidth tracking requires log parsing.
*/
export async function getAccessLogSizeMb(username: string): Promise<number> {
const logPath = `/var/log/apache2/${username}-access.log`
try {
const stat = await fs.stat(logPath)
return Math.round(stat.size / 1024 / 1024)
} catch {
return 0
}
}