warpgate/warpgate/src/cli/warmup.rs
grabbit 5d8bf52ae9 Add warpgate MVP implementation with hardened supervisor
Full Rust implementation of the warpgate NAS cache proxy:

- CLI: clap-based with subcommands (run, setup, status, cache, warmup,
  bwlimit, speed-test, config-init, log)
- Config: TOML-based with env var override, preset templates
- rclone: VFS mount args builder, config generator, RC API client
- Services: Samba config gen, NFS exports, WebDAV serve args, systemd units
- Deploy: dependency checker, filesystem validation, one-click setup
- Supervisor: single-process tree managing rclone mount + smbd + WebDAV
  as child processes — no systemd dependency for protocol management

Supervisor hardening:
- ProtocolChildren Drop impl prevents orphaned processes on startup failure
- Early rclone exit detection in mount wait loop (fail fast, not 30s timeout)
- Graceful SIGTERM → 3s grace → SIGKILL (prevents orphaned smbd workers)
- RestartTracker with 5-min stability reset and linear backoff (2s/4s/6s)
- Shutdown signal checked during mount wait and before protocol start

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 23:29:17 +08:00

46 lines
1.3 KiB
Rust

//! `warpgate warmup` — pre-cache a remote directory to local SSD.
use std::process::Command;
use anyhow::{Context, Result};
use crate::config::Config;
use crate::rclone::config as rclone_config;
pub fn run(config: &Config, path: &str, newer_than: Option<&str>) -> Result<()> {
let remote_src = format!("nas:{}/{}", config.connection.remote_path, path);
let local_dest = std::env::temp_dir().join("warpgate-warmup");
println!("Warming up: {}", remote_src);
// Create temp destination for downloaded files
std::fs::create_dir_all(&local_dest)
.context("Failed to create temp directory for warmup")?;
let mut cmd = Command::new("rclone");
cmd.arg("copy")
.arg("--config")
.arg(rclone_config::RCLONE_CONF_PATH)
.arg(&remote_src)
.arg(&local_dest)
.arg("--no-traverse")
.arg("--progress");
if let Some(age) = newer_than {
cmd.arg("--max-age").arg(age);
}
println!("Downloading from remote NAS...");
let status = cmd.status().context("Failed to run rclone copy")?;
// Clean up temp directory
let _ = std::fs::remove_dir_all(&local_dest);
if status.success() {
println!("Warmup complete.");
Ok(())
} else {
anyhow::bail!("rclone copy exited with status {}", status);
}
}