179 lines
5.2 KiB
Text
179 lines
5.2 KiB
Text
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
|
|
};
|
|
|
|
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();
|
|
}
|