feat: integrate rclone WebDAV backup for PC-to-PC file sync

Source PC serves backups/ folder via rclone WebDAV server (auto-starts with app).
Receiver PC pulls backups on schedule using rclone sync.
Network Backup UI now has two tabs: Rclone and API Key.
Rclone installed automatically via postinstall script.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ff
2026-06-24 23:29:36 -04:00
parent 24e66bfaf9
commit 5e881c9ff7
8 changed files with 723 additions and 148 deletions

View File

@@ -0,0 +1,50 @@
import fs from "fs";
import path from "path";
const CONFIG_FILE = path.resolve(process.cwd(), "rclone-config.json");
export const RCLONE_USER = "MyDentalApp";
export const RCLONE_PASS = "SuperSecret!@2026";
export interface RcloneConfig {
// Source role: serve backups folder via WebDAV
serverEnabled: boolean;
serverPort: number;
// Receiver role: pull backups from source PC
receiverEnabled: boolean;
receiverSyncHour: number;
sourceIp: string;
sourcePort: number;
lastSyncAt: string | null;
lastSyncStatus: string | null;
lastSyncError: string | null;
}
const DEFAULT_CONFIG: RcloneConfig = {
serverEnabled: false,
serverPort: 8080,
receiverEnabled: false,
receiverSyncHour: 21,
sourceIp: "",
sourcePort: 8080,
lastSyncAt: null,
lastSyncStatus: null,
lastSyncError: null,
};
export function readRcloneConfig(): RcloneConfig {
if (fs.existsSync(CONFIG_FILE)) {
try {
return { ...DEFAULT_CONFIG, ...JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8")) };
} catch {}
}
return { ...DEFAULT_CONFIG };
}
export function writeRcloneConfig(patch: Partial<RcloneConfig>): RcloneConfig {
const current = readRcloneConfig();
const updated = { ...current, ...patch };
fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), "utf8");
return updated;
}