Files
KiraTV-APP-NodeCast-Modific…/server/services/cache.js
T
2026-07-13 15:20:15 +00:00

152 lines
3.8 KiB
JavaScript

/**
* File-based Cache Service
* Stores cached data as JSON files in data/cache/
*/
const fs = require('fs');
const path = require('path');
// Cache directory
const cacheDir = path.join(__dirname, '..', '..', 'data', 'cache');
// Ensure cache directories exist
function ensureCacheDir(type, sourceId) {
const dir = path.join(cacheDir, type, String(sourceId));
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
return dir;
}
// Get cache file path
function getCachePath(type, sourceId, key) {
const dir = ensureCacheDir(type, sourceId);
// Sanitize key for filename
const safeKey = String(key || 'default').replace(/[^a-zA-Z0-9_-]/g, '_');
return path.join(dir, `${safeKey}.json`);
}
/**
* Get cached data if not expired
* @param {string} type - Cache type (epg, m3u, xtream)
* @param {number|string} sourceId - Source ID
* @param {string} key - Cache key (e.g., action name)
* @param {number} maxAgeMs - Maximum age in milliseconds
* @returns {any|null} - Cached data or null if expired/missing
*/
function get(type, sourceId, key, maxAgeMs) {
try {
const cachePath = getCachePath(type, sourceId, key);
if (!fs.existsSync(cachePath)) {
return null;
}
const cached = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
const age = Date.now() - cached.timestamp;
if (age > maxAgeMs) {
return null; // Expired
}
return cached.data;
} catch (err) {
console.warn(`Cache read error for ${type}/${sourceId}/${key}:`, err.message);
return null;
}
}
/**
* Store data in cache
* @param {string} type - Cache type
* @param {number|string} sourceId - Source ID
* @param {string} key - Cache key
* @param {any} data - Data to cache
*/
function set(type, sourceId, key, data) {
try {
const cachePath = getCachePath(type, sourceId, key);
const cached = {
timestamp: Date.now(),
data: data
};
fs.writeFileSync(cachePath, JSON.stringify(cached));
} catch (err) {
console.error(`Cache write error for ${type}/${sourceId}/${key}:`, err.message);
}
}
/**
* Clear specific cache entry
*/
function clear(type, sourceId, key) {
try {
const cachePath = getCachePath(type, sourceId, key);
if (fs.existsSync(cachePath)) {
fs.unlinkSync(cachePath);
}
} catch (err) {
console.warn(`Cache clear error:`, err.message);
}
}
/**
* Clear all cache for a source
*/
function clearSource(sourceId) {
try {
const types = ['epg', 'm3u', 'xtream'];
for (const type of types) {
const dir = path.join(cacheDir, type, String(sourceId));
if (fs.existsSync(dir)) {
fs.rmSync(dir, { recursive: true });
}
}
} catch (err) {
console.warn(`Cache clear source error:`, err.message);
}
}
/**
* Clear all cache
*/
function clearAll() {
try {
if (fs.existsSync(cacheDir)) {
fs.rmSync(cacheDir, { recursive: true });
}
} catch (err) {
console.warn(`Cache clear all error:`, err.message);
}
}
/**
* Get cache info for debugging
*/
function getInfo(type, sourceId, key) {
try {
const cachePath = getCachePath(type, sourceId, key);
if (!fs.existsSync(cachePath)) {
return null;
}
const cached = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
const stats = fs.statSync(cachePath);
return {
timestamp: cached.timestamp,
age: Date.now() - cached.timestamp,
size: stats.size
};
} catch (err) {
return null;
}
}
module.exports = {
get,
set,
clear,
clearSource,
clearAll,
getInfo
};