Signed-off-by: Omar Sánchez Pizarro <omar.sanchez@pistacero.net>
This commit is contained in:
Omar Sánchez Pizarro
2026-01-20 03:21:50 +01:00
parent 19932854ca
commit 81bf0675ed
32 changed files with 3081 additions and 932 deletions

View File

@@ -5,6 +5,7 @@ import bcrypt from 'bcrypt';
import { RateLimiterRedis } from 'rate-limiter-flexible';
import { PATHS } from '../config/constants.js';
import { RATE_LIMIT } from '../config/constants.js';
import { readJSON } from '../utils/fileUtils.js';
let redisClient = null;
let rateLimiter = null;
@@ -61,6 +62,9 @@ export async function initRedis() {
// Inicializar usuario admin por defecto si no existe
await initDefaultAdmin();
// Migrar workers.json a Redis para admin si no existe
await migrateWorkersFromFile();
} else {
console.log(' Redis no configurado, usando modo memoria');
console.log('⚠️ Rate limiting y autenticación requieren Redis');
@@ -157,6 +161,8 @@ export async function getNotifiedArticles() {
url: articleData.url || null,
images: articleData.images || [],
modified_at: articleData.modified_at || null,
username: articleData.username || null,
worker_name: articleData.worker_name || null,
notifiedAt: Date.now() - (7 * 24 * 60 * 60 - ttl) * 1000,
expiresAt: Date.now() + ttl * 1000,
});
@@ -217,3 +223,100 @@ export async function initNotifiedArticleKeys() {
}
}
// Funciones para manejar workers por usuario
export async function getWorkers(username) {
if (!redisClient) {
throw new Error('Redis no está disponible');
}
try {
const workersKey = `workers:${username}`;
const workersData = await redisClient.get(workersKey);
if (!workersData) {
// Retornar estructura vacía por defecto
return {
general: {
title_exclude: [],
description_exclude: []
},
items: [],
disabled: []
};
}
return JSON.parse(workersData);
} catch (error) {
console.error(`Error obteniendo workers para ${username}:`, error.message);
throw error;
}
}
export async function setWorkers(username, workers) {
if (!redisClient) {
throw new Error('Redis no está disponible');
}
try {
const workersKey = `workers:${username}`;
const workersData = JSON.stringify(workers);
await redisClient.set(workersKey, workersData);
return true;
} catch (error) {
console.error(`Error guardando workers para ${username}:`, error.message);
throw error;
}
}
// Migrar workers.json a Redis para el usuario admin si no existe
async function migrateWorkersFromFile() {
if (!redisClient) {
return;
}
try {
const adminWorkersKey = 'workers:admin';
const adminWorkersExists = await redisClient.exists(adminWorkersKey);
// Si ya existen workers para admin en Redis, no migrar
if (adminWorkersExists) {
console.log(' Workers de admin ya existen en Redis, omitiendo migración');
return;
}
// Intentar leer workers.json
if (!existsSync(PATHS.WORKERS)) {
console.log(' workers.json no existe, creando estructura vacía para admin');
// Crear estructura vacía por defecto
const defaultWorkers = {
general: {
title_exclude: [],
description_exclude: []
},
items: [],
disabled: []
};
await setWorkers('admin', defaultWorkers);
return;
}
// Leer workers.json y migrar a Redis
const workersData = readJSON(PATHS.WORKERS, {
general: {
title_exclude: [],
description_exclude: []
},
items: [],
disabled: []
});
// Guardar en Redis para admin
await setWorkers('admin', workersData);
console.log(`✅ Workers migrados desde workers.json al usuario admin (${workersData.items?.length || 0} items)`);
} catch (error) {
console.error('Error migrando workers.json a Redis:', error.message);
// No lanzar error, solo registrar
}
}