413 lines
7.7 KiB
JavaScript
413 lines
7.7 KiB
JavaScript
import readline from "readline";
|
|
import dotenv from "dotenv";
|
|
|
|
dotenv.config();
|
|
|
|
// ===============================
|
|
// CONFIG
|
|
// ===============================
|
|
|
|
const BASE_URL = process.env.BASE_URL;
|
|
|
|
if (!BASE_URL) {
|
|
console.error("ERRORE: BASE_URL non definita nel .env");
|
|
process.exit(1);
|
|
}
|
|
|
|
const WATCHER_TOKEN = process.env.WATCHER_TOKEN;
|
|
|
|
if (!WATCHER_TOKEN) {
|
|
console.error("ERRORE: WATCHER_TOKEN non definito nel .env");
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("Watcher globale avviato");
|
|
|
|
// ===============================
|
|
// STDIN
|
|
// ===============================
|
|
|
|
const rl = readline.createInterface({
|
|
input: process.stdin,
|
|
crlfDelay: Infinity
|
|
});
|
|
|
|
// ===============================
|
|
// ESTENSIONI FOTO / VIDEO
|
|
// ===============================
|
|
|
|
const photoExt = [
|
|
".jpg",
|
|
".jpeg",
|
|
".png",
|
|
".gif",
|
|
".bmp",
|
|
".webp",
|
|
".tiff",
|
|
".heic",
|
|
".heif",
|
|
".mp4",
|
|
".mov",
|
|
".avi",
|
|
".mkv",
|
|
".webm",
|
|
".m4v"
|
|
];
|
|
|
|
// ===============================
|
|
// ESTENSIONI ATTIVITÀ
|
|
// ===============================
|
|
|
|
const activityExt = [
|
|
".fit",
|
|
".gpx",
|
|
".tcx"
|
|
];
|
|
|
|
// ===============================
|
|
// PARSING PATH
|
|
// ===============================
|
|
|
|
function parsePath(fullPath) {
|
|
|
|
const normalized = fullPath.replace(/\\/g, "/");
|
|
|
|
/*
|
|
* Supporta sia:
|
|
*
|
|
* /app/photos/Fabio/original/...
|
|
* /app/activities/Fabio/original/...
|
|
*
|
|
* sia:
|
|
*
|
|
* ../public/photos/Fabio/original/...
|
|
* ../public/activities/Fabio/original/...
|
|
*
|
|
*/
|
|
|
|
const match = normalized.match(
|
|
/(?:^|\/)(photos|activities)\/([^/]+)\/original(?:\/|$)/
|
|
);
|
|
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
area: match[1],
|
|
user: match[2]
|
|
};
|
|
}
|
|
|
|
// ===============================
|
|
// NORMALIZZAZIONE PATH
|
|
// ===============================
|
|
|
|
function normalizePath(fullPath) {
|
|
|
|
const normalized = fullPath.replace(/\\/g, "/");
|
|
|
|
/*
|
|
* Trasforma:
|
|
*
|
|
* ../public/photos/Fabio/original/traptour/
|
|
*
|
|
* in:
|
|
*
|
|
* /photos/Fabio/original/traptour/
|
|
*
|
|
*
|
|
* e anche:
|
|
*
|
|
* /app/photos/Fabio/original/traptour/
|
|
*
|
|
* in:
|
|
*
|
|
* /photos/Fabio/original/traptour/
|
|
*/
|
|
|
|
const match = normalized.match(
|
|
/(?:^|\/)(photos|activities)\/(.+)$/
|
|
);
|
|
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
|
|
return `/${match[1]}/${match[2]}`;
|
|
}
|
|
|
|
// ===============================
|
|
// FILTRO FILE
|
|
// ===============================
|
|
|
|
function isAllowedFile(area, filename) {
|
|
|
|
const lower = filename.toLowerCase();
|
|
|
|
if (area === "photos") {
|
|
return photoExt.some(ext => lower.endsWith(ext));
|
|
}
|
|
|
|
if (area === "activities") {
|
|
return activityExt.some(ext => lower.endsWith(ext));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ===============================
|
|
// CHIAMATA API
|
|
// ===============================
|
|
|
|
async function callAutoScan(type, file, path, user) {
|
|
|
|
const relPath = normalizePath(path);
|
|
|
|
if (!relPath) {
|
|
console.error(
|
|
"Impossibile normalizzare path:",
|
|
path
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
const headers = {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${WATCHER_TOKEN}`
|
|
};
|
|
|
|
const payload = {
|
|
type,
|
|
file,
|
|
path: relPath,
|
|
user
|
|
};
|
|
|
|
console.log("AUTO_SCAN:", payload);
|
|
|
|
try {
|
|
|
|
const res = await fetch(
|
|
`${BASE_URL}/api_v1/auto_scan`,
|
|
{
|
|
method: "POST",
|
|
headers,
|
|
body: JSON.stringify(payload)
|
|
}
|
|
);
|
|
|
|
if (!res.ok) {
|
|
|
|
console.error(
|
|
`Errore auto_scan ${res.status}`
|
|
);
|
|
|
|
try {
|
|
const text = await res.text();
|
|
|
|
if (text) {
|
|
console.error(
|
|
"Risposta API:",
|
|
text
|
|
);
|
|
}
|
|
}
|
|
catch (_) {
|
|
// niente
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
console.log(
|
|
`AUTO_SCAN OK ${res.status}`
|
|
);
|
|
|
|
return true;
|
|
|
|
}
|
|
catch (err) {
|
|
|
|
console.error(
|
|
"Errore chiamata auto_scan:",
|
|
err
|
|
);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ===============================
|
|
// WATCHER
|
|
// ===============================
|
|
|
|
function startWatcher() {
|
|
|
|
rl.on("line", async line => {
|
|
|
|
console.log("RAW:", line);
|
|
|
|
try {
|
|
|
|
const parts = line.trim().split(/\s+/);
|
|
|
|
if (parts.length < 3) {
|
|
|
|
console.log(
|
|
"EVENTO SCARTATO: formato non valido"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
const path = parts[0];
|
|
const action = parts[1];
|
|
const file = parts.slice(2).join(" ");
|
|
|
|
console.log({
|
|
path,
|
|
action,
|
|
file
|
|
});
|
|
|
|
// ===============================
|
|
// PARSE PATH
|
|
// ===============================
|
|
|
|
const info = parsePath(path);
|
|
|
|
console.log(
|
|
"PARSE_PATH:",
|
|
info
|
|
);
|
|
|
|
if (!info) {
|
|
|
|
console.log(
|
|
"PATH IGNORATO"
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
const {
|
|
user,
|
|
area
|
|
} = info;
|
|
|
|
// ===============================
|
|
// DIRECTORY?
|
|
// ===============================
|
|
|
|
const isDir = action.includes("ISDIR");
|
|
|
|
// ===============================
|
|
// FILTRO ESTENSIONE
|
|
// ===============================
|
|
|
|
if (
|
|
!isDir &&
|
|
!isAllowedFile(area, file)
|
|
) {
|
|
|
|
console.log(
|
|
`FILE IGNORATO area=${area} file=${file}`
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
// ===============================
|
|
// TIPO EVENTO
|
|
// ===============================
|
|
|
|
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 {
|
|
|
|
console.log(
|
|
`AZIONE IGNORATA: ${action}`
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
// ===============================
|
|
// EVENTO
|
|
// ===============================
|
|
|
|
console.log(
|
|
`[${area}] ${user} -> ${type} ${file}`
|
|
);
|
|
|
|
// ===============================
|
|
// API
|
|
// ===============================
|
|
|
|
await callAutoScan(
|
|
type,
|
|
file,
|
|
path,
|
|
user
|
|
);
|
|
|
|
}
|
|
catch (err) {
|
|
|
|
console.error(
|
|
"Errore watcher:",
|
|
err
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
// ===============================
|
|
// START
|
|
// ===============================
|
|
|
|
startWatcher();
|