Files
Multi-Hoster-Upload/lib/log-rotation.js
T
Sucukdeluxe bfb3a39fed fix: harden upload cancellation and audit logging
Preserve pre-start and batch cancellation requests, reject late upload success after cancellation, and wait for cancellation acknowledgements before removing queue entries.

Separate formatted link logs from privacy-safe source cleanup and upload plan audits, persist audit fallback paths, redact support bundles, and expose audit diagnostics safely.

Improve queue selection and destructive-action clarity, show the Settings save action only while changes are pending, and add regression coverage for all updated behavior.
2026-08-13 14:31:46 +02:00

59 lines
2.2 KiB
JavaScript

// Generic numbered-backup log rotation. Used by the upload log + can be
// reused by other long-lived log files (debug log, account-rotation log).
//
// Behaviour:
// - File missing → no-op, returns false.
// - File ≤ maxBytes → no-op, returns false.
// - File > maxBytes → drop oldest .N backup, shift .K → .K+1, rename live
// file to .1, return true. Caller (or the next append) creates a fresh
// primary on demand.
//
// Errors are reported via `log` (e.g. debugLog) but never thrown — rotation
// is best-effort; the caller's append happens anyway.
const fs = require('fs');
const path = require('path');
function getRotatedLogPath(filePath, backup) {
const index = Number(backup);
if (!Number.isInteger(index) || index < 1) return filePath;
const ext = path.extname(filePath);
const base = filePath.slice(0, filePath.length - ext.length);
return `${base}.${index}${ext}`;
}
function maybeRotateLogFile(filePath, maxBytes, maxBackups = 3, log = () => {}) {
if (!filePath || !Number.isFinite(maxBytes) || maxBytes <= 0) return false;
let size = 0;
try {
const st = fs.statSync(filePath);
size = st.size;
} catch (err) {
// ENOENT is normal — nothing to rotate yet.
if (err && err.code !== 'ENOENT') {
log(`logRotation: stat ${filePath} failed: ${err.message}`);
}
return false;
}
if (size <= maxBytes) return false;
// Drop the oldest backup if it exists, then shift each numbered backup up
// one slot. Errors are ignored: missing intermediate backups are normal,
// failed renames just mean we'll rotate again next time.
try { fs.unlinkSync(getRotatedLogPath(filePath, maxBackups)); } catch {}
for (let i = maxBackups - 1; i >= 1; i--) {
try { fs.renameSync(getRotatedLogPath(filePath, i), getRotatedLogPath(filePath, i + 1)); } catch {}
}
try {
const backupPath = getRotatedLogPath(filePath, 1);
fs.renameSync(filePath, backupPath);
log(`logRotation: rotated ${filePath} (${(size / 1024 / 1024).toFixed(1)} MB) → ${backupPath}`);
return true;
} catch (err) {
log(`logRotation: rename ${filePath}${getRotatedLogPath(filePath, 1)} failed: ${err.message}`);
return false;
}
}
module.exports = { getRotatedLogPath, maybeRotateLogFile };