mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-05-25 07:20:41 +08:00
feat: add bulk delete for session manager (#1693)
* feat: add bulk delete for session manager * fix: address batch delete review issues * fix: keep session list in sync after batch delete
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
pub mod providers;
|
||||
pub mod terminal;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use providers::{claude, codex, gemini, openclaw, opencode};
|
||||
@@ -36,6 +36,25 @@ pub struct SessionMessage {
|
||||
pub ts: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeleteSessionRequest {
|
||||
pub provider_id: String,
|
||||
pub session_id: String,
|
||||
pub source_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeleteSessionOutcome {
|
||||
pub provider_id: String,
|
||||
pub session_id: String,
|
||||
pub source_path: String,
|
||||
pub success: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
pub fn scan_sessions() -> Vec<SessionMeta> {
|
||||
let (r1, r2, r3, r4, r5) = std::thread::scope(|s| {
|
||||
let h1 = s.spawn(codex::scan_sessions);
|
||||
@@ -99,6 +118,16 @@ pub fn delete_session(
|
||||
delete_session_with_root(provider_id, session_id, Path::new(source_path), &root)
|
||||
}
|
||||
|
||||
pub fn delete_sessions(requests: &[DeleteSessionRequest]) -> Vec<DeleteSessionOutcome> {
|
||||
collect_delete_session_outcomes(requests, |request| {
|
||||
delete_session(
|
||||
&request.provider_id,
|
||||
&request.session_id,
|
||||
&request.source_path,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn delete_session_with_root(
|
||||
provider_id: &str,
|
||||
session_id: &str,
|
||||
@@ -147,6 +176,41 @@ fn canonicalize_existing_path(path: &Path, label: &str) -> Result<PathBuf, Strin
|
||||
.map_err(|e| format!("Failed to resolve {label} {}: {e}", path.display()))
|
||||
}
|
||||
|
||||
fn collect_delete_session_outcomes<F>(
|
||||
requests: &[DeleteSessionRequest],
|
||||
mut deleter: F,
|
||||
) -> Vec<DeleteSessionOutcome>
|
||||
where
|
||||
F: FnMut(&DeleteSessionRequest) -> Result<bool, String>,
|
||||
{
|
||||
requests
|
||||
.iter()
|
||||
.map(|request| match deleter(request) {
|
||||
Ok(true) => DeleteSessionOutcome {
|
||||
provider_id: request.provider_id.clone(),
|
||||
session_id: request.session_id.clone(),
|
||||
source_path: request.source_path.clone(),
|
||||
success: true,
|
||||
error: None,
|
||||
},
|
||||
Ok(false) => DeleteSessionOutcome {
|
||||
provider_id: request.provider_id.clone(),
|
||||
session_id: request.session_id.clone(),
|
||||
source_path: request.source_path.clone(),
|
||||
success: false,
|
||||
error: Some("Session was not deleted".to_string()),
|
||||
},
|
||||
Err(error) => DeleteSessionOutcome {
|
||||
provider_id: request.provider_id.clone(),
|
||||
session_id: request.session_id.clone(),
|
||||
source_path: request.source_path.clone(),
|
||||
success: false,
|
||||
error: Some(error),
|
||||
},
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -175,4 +239,44 @@ mod tests {
|
||||
|
||||
assert!(err.contains("session source not found"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_delete_collects_successes_and_failures_in_order() {
|
||||
let requests = vec![
|
||||
DeleteSessionRequest {
|
||||
provider_id: "codex".to_string(),
|
||||
session_id: "s1".to_string(),
|
||||
source_path: "/tmp/s1".to_string(),
|
||||
},
|
||||
DeleteSessionRequest {
|
||||
provider_id: "claude".to_string(),
|
||||
session_id: "s2".to_string(),
|
||||
source_path: "/tmp/s2".to_string(),
|
||||
},
|
||||
DeleteSessionRequest {
|
||||
provider_id: "gemini".to_string(),
|
||||
session_id: "s3".to_string(),
|
||||
source_path: "/tmp/s3".to_string(),
|
||||
},
|
||||
];
|
||||
|
||||
let outcomes = collect_delete_session_outcomes(&requests, |request| {
|
||||
match request.session_id.as_str() {
|
||||
"s1" => Ok(true),
|
||||
"s2" => Err("boom".to_string()),
|
||||
_ => Ok(false),
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(outcomes.len(), 3);
|
||||
assert!(outcomes[0].success);
|
||||
assert_eq!(outcomes[0].error, None);
|
||||
assert!(!outcomes[1].success);
|
||||
assert_eq!(outcomes[1].error.as_deref(), Some("boom"));
|
||||
assert!(!outcomes[2].success);
|
||||
assert_eq!(
|
||||
outcomes[2].error.as_deref(),
|
||||
Some("Session was not deleted")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user