// services/syncJobs.js // This file handles both import { spawn } from 'node:child_process'; function runCmd(bin, args) { return new Promise((resolve, reject) => { console.log(`[EXEC] ${bin} ${args.join(' ')}`); const proc = spawn(bin, args, { stdio: 'inherit' }); proc.on('error', reject); proc.on('close', (code) => { if (code === 0) resolve(); else reject(new Error(`${bin} failed with exit code ${code}`)); }); }); } export async function runRsync(config) { const cfg = config.rsync; if (!cfg?.enabled) return; const mountPoint = config.system.mountPoint; const excludes = (cfg.exclude || []).flatMap((pattern) => ['--exclude', pattern]); console.log('[RSYNC] Syncing with NAS...'); await runCmd('rsync', [...cfg.flags, ...excludes, `${mountPoint}/`, `${cfg.nasPath}/`]); if (cfg.bidirectional) { await runCmd('rsync', [ ...cfg.flags, '--ignore-existing', ...excludes, `${cfg.nasPath}/`, `${mountPoint}/` ]); } } export async function runRclone(config) { const cfg = config.rclone; if (!cfg?.enabled) return; const mountPoint = config.system.mountPoint; const excludes = (cfg.exclude || []).flatMap((pattern) => ['--exclude', pattern]); console.log('[RCLONE] Syncing with cloud...'); await runCmd('rclone', ['copy', ...cfg.flags, ...excludes, mountPoint, cfg.remote]); if (cfg.bidirectional) { await runCmd('rclone', [ 'copy', '--ignore-existing', ...cfg.flags, ...excludes, cfg.remote, mountPoint ]); } }