feat: Implement dedicated data fetchers and utilities for categories, products, and images, and add server compression.
This commit is contained in:
134
src/utils/file-sync-utils.js
Normal file
134
src/utils/file-sync-utils.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* File synchronization utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get existing IDs from files in a directory
|
||||
* @param {string} dir - Directory path
|
||||
* @param {Object} options - Configuration options
|
||||
* @param {string} options.prefix - File prefix to filter (e.g., 'category_')
|
||||
* @param {string} options.suffix - File suffix to filter (e.g., '.json')
|
||||
* @param {RegExp} options.pattern - Custom regex pattern to extract ID
|
||||
* @returns {Promise<number[]>} - Array of numeric IDs
|
||||
*/
|
||||
export async function getExistingIds(dir, options = {}) {
|
||||
const { prefix = '', suffix = '', pattern = null } = options;
|
||||
|
||||
let existingFiles = [];
|
||||
try {
|
||||
existingFiles = await fs.readdir(dir);
|
||||
} catch (err) {
|
||||
// Directory might be empty or new
|
||||
return [];
|
||||
}
|
||||
|
||||
if (pattern) {
|
||||
return existingFiles
|
||||
.map(f => {
|
||||
const match = f.match(pattern);
|
||||
return match ? parseInt(match[1]) : null;
|
||||
})
|
||||
.filter(id => id !== null && !isNaN(id));
|
||||
}
|
||||
|
||||
return existingFiles
|
||||
.filter(f => {
|
||||
if (prefix && !f.startsWith(prefix)) return false;
|
||||
if (suffix && !f.endsWith(suffix)) return false;
|
||||
return true;
|
||||
})
|
||||
.map(f => {
|
||||
let id = f;
|
||||
if (prefix) id = id.replace(prefix, '');
|
||||
if (suffix) id = id.replace(suffix, '');
|
||||
return parseInt(id);
|
||||
})
|
||||
.filter(id => !isNaN(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete obsolete files based on valid IDs
|
||||
* @param {string} dir - Directory path
|
||||
* @param {number[]} existingIds - IDs of existing files
|
||||
* @param {Set<number>} validIds - Set of valid IDs to keep
|
||||
* @param {Function} filenameFn - Function to generate filename from ID
|
||||
* @returns {Promise<number>} - Number of files deleted
|
||||
*/
|
||||
export async function deleteObsoleteFiles(dir, existingIds, validIds, filenameFn) {
|
||||
const toDelete = existingIds.filter(id => !validIds.has(id));
|
||||
|
||||
for (const id of toDelete) {
|
||||
const filePath = path.join(dir, filenameFn(id));
|
||||
await fs.unlink(filePath);
|
||||
}
|
||||
|
||||
if (toDelete.length > 0) {
|
||||
console.log(`🗑️ Deleted ${toDelete.length} obsolete files.`);
|
||||
}
|
||||
|
||||
return toDelete.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write JSON to file only if content has changed
|
||||
* @param {string} filePath - Full path to file
|
||||
* @param {*} data - Data to write (will be JSON.stringify'd)
|
||||
* @param {number} indent - JSON indentation (default: 2)
|
||||
* @returns {Promise<boolean>} - True if file was written, false if unchanged
|
||||
*/
|
||||
export async function writeJsonIfChanged(filePath, data, indent = 2) {
|
||||
const newContent = JSON.stringify(data, null, indent);
|
||||
|
||||
let oldContent = '';
|
||||
try {
|
||||
oldContent = await fs.readFile(filePath, 'utf-8');
|
||||
} catch (e) {
|
||||
// File doesn't exist yet
|
||||
}
|
||||
|
||||
if (oldContent !== newContent) {
|
||||
await fs.writeFile(filePath, newContent);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure directory exists, create if it doesn't
|
||||
* @param {string} dir - Directory path
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function ensureDir(dir) {
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Read JSON file safely
|
||||
* @param {string} filePath - Full path to file
|
||||
* @returns {Promise<*|null>} - Parsed JSON or null if file doesn't exist
|
||||
*/
|
||||
export async function readJsonFile(filePath) {
|
||||
try {
|
||||
const content = await fs.readFile(filePath, 'utf-8');
|
||||
return JSON.parse(content);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read text file safely
|
||||
* @param {string} filePath - Full path to file
|
||||
* @returns {Promise<string|null>} - File content or null if file doesn't exist
|
||||
*/
|
||||
export async function readTextFile(filePath) {
|
||||
try {
|
||||
return await fs.readFile(filePath, 'utf-8');
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user