refactor(rclone): cache temizlemeyi RC API üzerinden yap

Rclone cache temizleme işlemini artık mount durdurup başlatmak yerine
RC API'nin vfs/forget komutunu kullanarak yapar. Bu yöntem daha hızlı ve
daha güvenli bir temizleme sağlar. RC API devre dışıyken cache temizleme
işlemi yapılmaz ve uyarı döner. Ayrıca mount dizinindeki bağlantı
sorunları (ENOTCONN) için otomatik unmount mekanizması eklendi.
This commit is contained in:
2026-02-02 15:51:18 +03:00
parent cd4769b3c1
commit e44c21b36a

View File

@@ -7,7 +7,7 @@ import path from "path";
import mime from "mime-types"; import mime from "mime-types";
import { v2 as webdav } from "webdav-server"; import { v2 as webdav } from "webdav-server";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import { exec, spawn } from "child_process"; import { exec, execSync, spawn } from "child_process";
import crypto from "crypto"; // 🔒 basit token üretimi için import crypto from "crypto"; // 🔒 basit token üretimi için
import { getDiskSpace, getDownloadsSize } from "./utils/diskSpace.js"; import { getDiskSpace, getDownloadsSize } from "./utils/diskSpace.js";
import { createAuth } from "./modules/auth.js"; import { createAuth } from "./modules/auth.js";
@@ -1004,11 +1004,17 @@ function startRcloneCacheCleanSchedule(minutes) {
if (!interval || interval <= 0) return; if (!interval || interval <= 0) return;
rcloneCacheCleanTimer = setInterval(() => { rcloneCacheCleanTimer = setInterval(() => {
if (!RCLONE_RC_ENABLED) return; if (!RCLONE_RC_ENABLED) return;
fetch(`http://${RCLONE_RC_ADDR}/vfs/refresh`, { method: "POST" }) fetch(`http://${RCLONE_RC_ADDR}/vfs/forget`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: "", recursive: true })
})
.then((resp) => { .then((resp) => {
if (resp.status === 404) { if (resp.status === 404) {
return fetch(`http://${RCLONE_RC_ADDR}/rc/vfs/refresh`, { return fetch(`http://${RCLONE_RC_ADDR}/rc/vfs/forget`, {
method: "POST" method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: "", recursive: true })
}); });
} }
return resp; return resp;
@@ -1023,21 +1029,37 @@ function startRcloneCacheCleanSchedule(minutes) {
} }
async function runRcloneCacheClean() { async function runRcloneCacheClean() {
const settings = loadRcloneSettings();
const wasRunning = Boolean(rcloneProcess && !rcloneProcess.killed); const wasRunning = Boolean(rcloneProcess && !rcloneProcess.killed);
if (wasRunning) {
stopRcloneMount();
}
try { try {
if (wasRunning && RCLONE_RC_ENABLED) {
const resp = await fetch(`http://${RCLONE_RC_ADDR}/vfs/forget`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: "", recursive: true })
});
if (resp.status === 404) {
const fallback = await fetch(`http://${RCLONE_RC_ADDR}/rc/vfs/forget`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: "", recursive: true })
});
if (!fallback.ok) {
const body = await fallback.text();
return { ok: false, error: `Rclone RC hata: ${body || fallback.status}` };
}
} else if (!resp.ok) {
const body = await resp.text();
return { ok: false, error: `Rclone RC hata: ${body || resp.status}` };
}
return { ok: true, method: "rc", restarted: false };
}
if (wasRunning && !RCLONE_RC_ENABLED) {
return { ok: false, error: "Rclone RC kapalıyken mount durdurulmadan cache temizlenemez." };
}
fs.rmSync(RCLONE_VFS_CACHE_DIR, { recursive: true, force: true }); fs.rmSync(RCLONE_VFS_CACHE_DIR, { recursive: true, force: true });
fs.mkdirSync(RCLONE_VFS_CACHE_DIR, { recursive: true }); fs.mkdirSync(RCLONE_VFS_CACHE_DIR, { recursive: true });
if (wasRunning) {
const result = startRcloneMount(settings);
if (!result.ok) {
return { ok: false, error: result.error || "Rclone yeniden başlatılamadı" };
}
return { ok: true, method: "fs", restarted: true };
}
return { ok: true, method: "fs", restarted: false }; return { ok: true, method: "fs", restarted: false };
} catch (err) { } catch (err) {
return { ok: false, error: err?.message || String(err) }; return { ok: false, error: err?.message || String(err) };
@@ -1058,8 +1080,23 @@ function isRcloneMounted(mountDir) {
function ensureRcloneDirs(settings) { function ensureRcloneDirs(settings) {
if (!settings?.mountDir) return; if (!settings?.mountDir) return;
if (!fs.existsSync(settings.mountDir)) { const mountDir = settings.mountDir;
fs.mkdirSync(settings.mountDir, { recursive: true }); try {
if (!fs.existsSync(mountDir)) {
fs.mkdirSync(mountDir, { recursive: true });
}
} catch (err) {
if (err?.code === "ENOTCONN") {
try {
execSync(`fusermount -u ${JSON.stringify(mountDir)}`, { stdio: "ignore" });
} catch {}
try {
execSync(`umount -l ${JSON.stringify(mountDir)}`, { stdio: "ignore" });
} catch {}
fs.mkdirSync(mountDir, { recursive: true });
} else {
throw err;
}
} }
if (!fs.existsSync(RCLONE_VFS_CACHE_DIR)) { if (!fs.existsSync(RCLONE_VFS_CACHE_DIR)) {
fs.mkdirSync(RCLONE_VFS_CACHE_DIR, { recursive: true }); fs.mkdirSync(RCLONE_VFS_CACHE_DIR, { recursive: true });