remove unnecessary command

This commit is contained in:
FTCHD
2026-07-12 00:30:36 +03:00
parent a07fb0b093
commit 1f8b51310e
3 changed files with 1 additions and 223 deletions
-11
View File
@@ -127,17 +127,6 @@ export async function schedulerReadLog(taskId: string, which: 'runner' | 'daemon
})
}
export interface SchedulerDoctorCheck {
name: string
ok: boolean
detail: string
fix?: string
}
export async function schedulerDoctor() {
return invoke<SchedulerDoctorCheck[]>('scheduler_doctor')
}
function buildJobSpec(task: ScheduledTask): SchedulerJobSpec {
return {
schemaVersion: 1,
-1
View File
@@ -885,7 +885,6 @@ pub fn run() {
scheduler::scheduler_status,
scheduler::scheduler_read_history,
scheduler::scheduler_read_log,
scheduler::scheduler_doctor,
scheduler::scheduler_unregister_all,
scheduler::scheduler_sweep_orphans,
notifications::notifications_catalog,
+1 -211
View File
@@ -346,7 +346,7 @@ pub fn scheduler_validate_cron(cron: String) -> CronValidation {
valid: true,
error: None,
next_runs: cronconv::parse(&cron)
.map(|spec| cronconv::next_fires(&spec, chrono::Local::now(), 5))
.map(|spec| cronconv::next_fires(&spec, chrono::Local::now(), 10))
.unwrap_or_default(),
},
Err(error) => CronValidation {
@@ -664,216 +664,6 @@ pub async fn scheduler_read_history(
.map_err(|e| e.to_string())?
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DoctorCheck {
pub name: String,
pub ok: bool,
pub detail: String,
pub fix: Option<String>,
}
/// Preflight diagnostics with actionable fixes — the "why didn't my task run" surface.
#[tauri::command]
pub async fn scheduler_doctor() -> Result<Vec<DoctorCheck>, String> {
tauri::async_runtime::spawn_blocking(move || {
let mut checks: Vec<DoctorCheck> = Vec::new();
if crate::is_flatpak() {
// Scheduling works under Flatpak through the host's cron (crontab via
// `flatpak-spawn --host`, entries re-launch the app with `flatpak run`). The startup
// gate normally guarantees these permissions; verify anyway so the doctor stays
// truthful if that gate ever changes.
let ok = crate::has_flatpak_permissions();
checks.push(DoctorCheck {
name: "Sandbox host access".to_string(),
ok,
detail: if ok {
"host filesystem and host-spawn access are granted — scheduling uses the host's cron"
.to_string()
} else {
"missing host filesystem or host-spawn permission — the app cannot reach the host's crontab"
.to_string()
},
fix: if ok {
None
} else {
Some(format!(
"Grant it: flatpak override --user --filesystem=host --talk-name=org.freedesktop.Flatpak {}",
flatpak_app_id()
))
},
});
if !ok {
return Ok(checks);
}
}
#[cfg(unix)]
{
match crontab::check_available() {
Ok(()) => checks.push(DoctorCheck {
name: "cron installed".to_string(),
ok: true,
detail: if crate::is_flatpak() {
"crontab found on the host".to_string()
} else {
"crontab found in PATH".to_string()
},
fix: None,
}),
Err(_) => {
checks.push(DoctorCheck {
name: "cron installed".to_string(),
ok: false,
detail: if crate::is_flatpak() {
"no crontab binary found on the host".to_string()
} else {
"no crontab binary found in PATH".to_string()
},
fix: Some(
"Install 'cron' (Debian/Ubuntu) or 'cronie' (Fedora/Arch), then restart the app."
.to_string(),
),
});
return Ok(checks);
}
}
match crontab::host_command("crontab").arg("-l").output() {
Ok(output) if output.status.success() => {
let managed = String::from_utf8_lossy(&output.stdout)
.lines()
.filter(|line| line.trim_start().starts_with("# rclone-ui-task:"))
.count();
checks.push(DoctorCheck {
name: "crontab access".to_string(),
ok: true,
detail: format!("{} scheduled task(s) registered", managed),
fix: None,
});
}
Ok(output) => {
let stderr = String::from_utf8_lossy(&output.stderr);
if crontab::stderr_means_no_crontab(&stderr) {
checks.push(DoctorCheck {
name: "crontab access".to_string(),
ok: true,
detail: "no crontab yet — created on first schedule".to_string(),
fix: None,
});
} else {
checks.push(DoctorCheck {
name: "crontab access".to_string(),
ok: false,
detail: format!("crontab -l failed: {}", stderr.trim()),
fix: Some(
"Your user may be denied cron access (cron.deny / system policy)."
.to_string(),
),
});
}
}
Err(e) => checks.push(DoctorCheck {
name: "crontab access".to_string(),
ok: false,
detail: format!("could not run crontab: {}", e),
fix: None,
}),
}
}
#[cfg(target_os = "linux")]
{
// Inside the Flatpak sandbox (own PID namespace) host processes are invisible to
// sysinfo — list them on the host instead.
let cron_running = if crate::is_flatpak() {
crontab::host_command("sh")
.arg("-c")
.arg("ps -e -o comm=")
.output()
.map(|o| {
String::from_utf8_lossy(&o.stdout)
.lines()
.any(|name| matches!(name.trim(), "cron" | "crond" | "cronie"))
})
.unwrap_or(false)
} else {
let mut system = sysinfo::System::new();
system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
system.processes().values().any(|process| {
let name = process.name().to_string_lossy().to_lowercase();
name == "cron" || name == "crond" || name == "cronie"
})
};
checks.push(DoctorCheck {
name: "cron service".to_string(),
ok: cron_running,
detail: if cron_running {
"cron daemon is running".to_string()
} else {
"no cron daemon process found — schedules will not fire".to_string()
},
fix: if cron_running {
None
} else {
Some("Enable it: sudo systemctl enable --now cron (or cronie)".to_string())
},
});
}
#[cfg(target_os = "macos")]
{
// TCC is the common silent failure for tasks touching Desktop/Documents/Downloads or
// external/network volumes. The fix differs by run mode: user-mode tasks run as the
// app via a LaunchAgent (grant the app), system-mode tasks run under cron (grant cron).
checks.push(DoctorCheck {
name: "macOS privacy (TCC)".to_string(),
ok: true,
detail:
"Tasks reading protected folders (Desktop, Documents, Downloads) or external/network volumes may be blocked by macOS privacy protections. A scheduled run cannot show a permission prompt, so access must be granted beforehand."
.to_string(),
fix: Some(
"'User' run mode (default): grant Rclone UI access to the folder, or add Rclone UI to Full Disk Access in System Settings → Privacy & Security. 'System' run mode: grant Full Disk Access to /usr/sbin/cron instead."
.to_string(),
),
});
}
#[cfg(target_os = "windows")]
{
let query = std::process::Command::new("schtasks").arg("/Query").output();
let ok = query.map(|o| o.status.success()).unwrap_or(false);
checks.push(DoctorCheck {
name: "Task Scheduler".to_string(),
ok,
detail: if ok {
"Task Scheduler service is reachable".to_string()
} else {
"schtasks query failed — the Task Scheduler service may be disabled".to_string()
},
fix: if ok {
None
} else {
Some("Start the 'Task Scheduler' service (services.msc).".to_string())
},
});
checks.push(DoctorCheck {
name: "Runs while logged out".to_string(),
ok: true,
detail:
"Schedules in 'System' run mode run while logged out (S4U) but cannot access mapped drives or implicit-auth network shares — schedules that need them should use the 'User' run mode. S4U also requires the 'Log on as a batch job' right: on domain-managed machines that deny it, System-mode tasks register but never start."
.to_string(),
fix: None,
});
}
Ok(checks)
})
.await
.map_err(|e| e.to_string())?
}
/// Remove every registration this app ever made (Settings escape hatch / pre-uninstall cleanup).
/// Sweeps both job files and orphaned OS artifacts by prefix.
#[tauri::command]