fix: harden scheduler, permissions, and download safety

- Implement scheduler hydration barrier to prevent premature triggers
- Track scheduler exact runs using keys to avoid false stops
- Use 'System Events' for accurate macOS automation permissions
- Prevent system-sleep via proper idle assertions
- Ensure download pauses use channel acknowledgements (PauseWithAck)
- Require Firelink ownership before replacing files in add/conflict UI
- Retain partial download assets when removing entries without deletion
- Clear progress state in store when downloads complete or pause to reduce churn
- Handle empty/invalid queue selections gracefully
This commit is contained in:
NimBold
2026-06-22 18:05:04 +03:30
parent 6b3753949b
commit 7c835b022f
17 changed files with 529 additions and 181 deletions
+55 -1
View File
@@ -43,6 +43,26 @@ pub fn update_settings_state(
crate::db::save_settings(&connection, &stored)
}
pub fn preserve_scheduler_runtime_keys(
existing: Option<&str>,
incoming: &str,
) -> Result<String, String> {
let Some(existing) = existing else {
return Ok(incoming.to_string());
};
let existing_document = decode_document(&Value::String(existing.to_string()))?;
let existing_state = settings_state(&existing_document)?;
let mut incoming_document = decode_document(&Value::String(incoming.to_string()))?;
let incoming_state = settings_state_mut(&mut incoming_document)?;
for key in ["schedulerLastStartKey", "schedulerLastStopKey"] {
if let Some(value) = existing_state.get(key) {
incoming_state.insert(key.to_string(), value.clone());
}
}
serde_json::to_string(&incoming_document)
.map_err(|error| format!("failed to encode persisted settings: {error}"))
}
fn decode_document(stored: &Value) -> Result<Value, String> {
match stored {
Value::String(text) => serde_json::from_str(text)
@@ -246,6 +266,8 @@ fn default_settings() -> PersistedSettings {
selected_queue_ids: vec!["00000000-0000-0000-0000-000000000001".to_string()],
post_queue_action: PostQueueAction::None,
},
scheduler_running: false,
scheduler_active_download_ids: Vec::new(),
scheduler_last_start_key: String::new(),
scheduler_last_stop_key: String::new(),
last_custom_speed_limit_ki_b: 1024,
@@ -271,9 +293,41 @@ fn default_settings() -> PersistedSettings {
#[cfg(test)]
mod tests {
use super::decode_stored_settings;
use super::{decode_stored_settings, preserve_scheduler_runtime_keys};
use serde_json::{json, Value};
#[test]
fn frontend_settings_save_preserves_backend_scheduler_keys() {
let existing = json!({
"state": {
"schedulerLastStartKey": "2026-06-22-start",
"schedulerLastStopKey": "2026-06-22-stop"
},
"version": 3
})
.to_string();
let incoming = json!({
"state": {
"schedulerLastStartKey": "",
"schedulerLastStopKey": "",
"theme": "system"
},
"version": 3
})
.to_string();
let merged = preserve_scheduler_runtime_keys(Some(&existing), &incoming).unwrap();
let merged: Value = serde_json::from_str(&merged).unwrap();
assert_eq!(
merged["state"]["schedulerLastStartKey"],
"2026-06-22-start"
);
assert_eq!(
merged["state"]["schedulerLastStopKey"],
"2026-06-22-stop"
);
}
#[test]
fn decodes_zustand_envelope_and_preserves_non_default_startup_settings() {
let stored = json!({