fix: harden backend stability and test production utilities
This commit is contained in:
107
backend/utils/download-quota.js
Normal file
107
backend/utils/download-quota.js
Normal file
@@ -0,0 +1,107 @@
|
||||
const {
|
||||
parseDateTimeValue,
|
||||
formatDateTimeForSqlite,
|
||||
getNextDownloadResetTime
|
||||
} = require('./datetime');
|
||||
|
||||
const MAX_DOWNLOAD_TRAFFIC_BYTES = 10 * 1024 * 1024 * 1024 * 1024;
|
||||
|
||||
function normalizeDownloadTrafficQuota(rawQuota) {
|
||||
const parsedQuota = Number(rawQuota);
|
||||
if (!Number.isFinite(parsedQuota)) return 0;
|
||||
if (parsedQuota < 0) return -1;
|
||||
return Math.min(MAX_DOWNLOAD_TRAFFIC_BYTES, Math.floor(parsedQuota));
|
||||
}
|
||||
|
||||
function normalizeDownloadTrafficUsed(rawUsed, quota = 0) {
|
||||
const parsedUsed = Number(rawUsed);
|
||||
const normalizedUsed = Number.isFinite(parsedUsed) && parsedUsed > 0
|
||||
? Math.floor(parsedUsed)
|
||||
: 0;
|
||||
return quota >= 0 ? Math.min(normalizedUsed, quota) : normalizedUsed;
|
||||
}
|
||||
|
||||
function getDownloadTrafficState(user) {
|
||||
const quota = normalizeDownloadTrafficQuota(user?.download_traffic_quota);
|
||||
const used = normalizeDownloadTrafficUsed(user?.download_traffic_used, quota);
|
||||
const isUnlimited = quota < 0;
|
||||
return {
|
||||
quota,
|
||||
used,
|
||||
isUnlimited,
|
||||
remaining: isUnlimited ? Number.POSITIVE_INFINITY : Math.max(0, quota - used)
|
||||
};
|
||||
}
|
||||
|
||||
function resolveDownloadTrafficPolicyUpdates(user, now = new Date()) {
|
||||
if (!user) {
|
||||
return { updates: {}, hasUpdates: false, expired: false, resetApplied: false };
|
||||
}
|
||||
|
||||
const updates = {};
|
||||
let hasUpdates = false;
|
||||
let expired = false;
|
||||
let resetApplied = false;
|
||||
|
||||
const normalizedQuota = normalizeDownloadTrafficQuota(user.download_traffic_quota);
|
||||
const normalizedUsed = normalizeDownloadTrafficUsed(user.download_traffic_used, normalizedQuota);
|
||||
if (normalizedQuota !== Number(user.download_traffic_quota || 0)) {
|
||||
updates.download_traffic_quota = normalizedQuota;
|
||||
hasUpdates = true;
|
||||
}
|
||||
if (normalizedUsed !== Number(user.download_traffic_used || 0)) {
|
||||
updates.download_traffic_used = normalizedUsed;
|
||||
hasUpdates = true;
|
||||
}
|
||||
|
||||
const resetCycle = ['none', 'daily', 'weekly', 'monthly'].includes(user.download_traffic_reset_cycle)
|
||||
? user.download_traffic_reset_cycle
|
||||
: 'none';
|
||||
if (resetCycle !== (user.download_traffic_reset_cycle || 'none')) {
|
||||
updates.download_traffic_reset_cycle = resetCycle;
|
||||
hasUpdates = true;
|
||||
}
|
||||
|
||||
const expiresAt = parseDateTimeValue(user.download_traffic_quota_expires_at);
|
||||
if (normalizedQuota <= 0 && user.download_traffic_quota_expires_at) {
|
||||
updates.download_traffic_quota_expires_at = null;
|
||||
hasUpdates = true;
|
||||
} else if (normalizedQuota > 0 && expiresAt && now >= expiresAt) {
|
||||
updates.download_traffic_quota = -1;
|
||||
updates.download_traffic_used = 0;
|
||||
updates.download_traffic_quota_expires_at = null;
|
||||
updates.download_traffic_reset_cycle = 'none';
|
||||
updates.download_traffic_last_reset_at = null;
|
||||
hasUpdates = true;
|
||||
expired = true;
|
||||
}
|
||||
|
||||
if (!expired && resetCycle !== 'none') {
|
||||
const lastResetAt = user.download_traffic_last_reset_at;
|
||||
if (!lastResetAt) {
|
||||
updates.download_traffic_last_reset_at = formatDateTimeForSqlite(now);
|
||||
hasUpdates = true;
|
||||
} else {
|
||||
const nextResetAt = getNextDownloadResetTime(lastResetAt, resetCycle);
|
||||
if (nextResetAt && now >= nextResetAt) {
|
||||
updates.download_traffic_used = 0;
|
||||
updates.download_traffic_last_reset_at = formatDateTimeForSqlite(now);
|
||||
hasUpdates = true;
|
||||
resetApplied = true;
|
||||
}
|
||||
}
|
||||
} else if (resetCycle === 'none' && user.download_traffic_last_reset_at) {
|
||||
updates.download_traffic_last_reset_at = null;
|
||||
hasUpdates = true;
|
||||
}
|
||||
|
||||
return { updates, hasUpdates, expired, resetApplied };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
MAX_DOWNLOAD_TRAFFIC_BYTES,
|
||||
normalizeDownloadTrafficQuota,
|
||||
normalizeDownloadTrafficUsed,
|
||||
getDownloadTrafficState,
|
||||
resolveDownloadTrafficPolicyUpdates
|
||||
};
|
||||
Reference in New Issue
Block a user