import readline from "readline"; import fs from "fs"; import dotenv from "dotenv"; dotenv.config(); const user = process.argv[2]; // =============================== // BASE_URL DAL .env // =============================== const BASE_URL = process.env.BASE_URL; if (!BASE_URL) { console.error("ERRORE: BASE_URL non definita in .env"); process.exit(1); } // =============================== // CREDENZIALI ADMIN // =============================== const adminSecret = JSON.parse(fs.readFileSync("/app/config/admin_secret.json", "utf8")); let adminToken = null; let isRefreshing = false; // =============================== // LOGIN ADMIN (solo Admin lo usa) // =============================== async function loginAdmin() { while (true) { try { const res = await fetch(`${BASE_URL}/auth/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: adminSecret.email, password: adminSecret.password }) }); if (!res.ok) { const now = new Date().toISOString(); console.error(`[${now}] [Admin] Login fallito (${res.status}). Riprovo tra 20 secondi...`); await new Promise(r => setTimeout(r, 20000)); continue; } const data = await res.json(); adminToken = data.token; const now = new Date().toISOString(); console.log(`[${now}] Watcher autenticato come Admin`); return; } catch (err) { const now = new Date().toISOString(); console.error(`[${now}] [Admin] Connessione al server fallita. Riprovo tra 20 secondi...`); await new Promise(r => setTimeout(r, 20000)); } } } // =============================== // GARANTISCE TOKEN VALIDO (solo Admin) // =============================== async function ensureAdminToken() { if (adminToken) return; if (isRefreshing) { return new Promise(resolve => { const interval = setInterval(() => { if (!isRefreshing) { clearInterval(interval); resolve(); } }, 100); }); } isRefreshing = true; await loginAdmin(); isRefreshing = false; } // =============================== // CHIAMATA A /auto_scan // =============================== async function callAutoScan(type, file, path, user) { // Admin ottiene il token // Gli altri utenti aspettano che Admin lo abbia await ensureAdminToken(); const headers = { "Content-Type": "application/json", "Authorization": "Bearer " + adminToken // 🔥 tutti usano il token di Admin }; path = path.replace(/^\/app/, ""); const res = await fetch(`${BASE_URL}/api_v1/auto_scan`, { method: "POST", headers, body: JSON.stringify({ type, file, path, user }) }); // Se il token scade, Admin lo rinnova if (res.status === 401) { console.log(`[${new Date().toISOString()}] Token scaduto, rinnovo…`); adminToken = null; return callAutoScan(type, file, path, user); } return res.ok; } // =============================== // ESTENSIONI MEDIA // =============================== const photoExt = [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".tiff", ".heic", ".heif"]; const videoExt = [".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"]; function isMediaFile(filename) { const lower = filename.toLowerCase(); return photoExt.some(ext => lower.endsWith(ext)) || videoExt.some(ext => lower.endsWith(ext)); } console.log(`Node attivo per utente: ${user}`); const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity }); // =============================== // LOGICA EVENTI // =============================== function startWatcher() { rl.on("line", line => { const parts = line.trim().split(/\s+/); const path = parts[0]; const action = parts[1]; const file = parts[2]; if (!file) return; const isDir = action.includes("ISDIR"); if (!isDir && !isMediaFile(file)) { console.log(`Ignorato (non media): ${file}`); return; } let type = null; if (action === "MOVED_TO,ISDIR") type = "ADD_DIR"; else if (action === "MOVED_FROM,ISDIR") type = "DEL_DIR"; else if (/^CLOSE_WRITE(,CLOSE)?$/.test(action)) type = "ADD"; else if (action === "MOVED_TO") type = "ADD"; else if (action === "MOVED_FROM") type = "DEL"; else if (action === "DELETE") type = "DEL"; else return; console.log(`${type} ${file} ${path} ${user}`); callAutoScan(type, file, path, user); }); } // =============================== // AVVIO: SOLO ADMIN FA LOGIN // =============================== if (user === "Admin") { loginAdmin().then(() => { startWatcher(); }); } else { console.log(`Watcher per ${user} avviato senza login`); startWatcher(); }