use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;
use std::path::PathBuf;
use crate::duplicates::{DuplicateGroup, ScanSummary};
pub const SESSION_VERSION: u32 = 2;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Session {
pub version: u32,
pub created_at: DateTime<Utc>,
pub scan_paths: Vec<PathBuf>,
pub settings: SessionSettings,
pub groups: Vec<SessionGroup>,
pub user_selections: BTreeSet<PathBuf>,
pub group_index: usize,
pub file_index: usize,
}
impl Session {
pub fn new(
scan_paths: Vec<PathBuf>,
settings: SessionSettings,
groups: Vec<SessionGroup>,
) -> Self {
Self {
version: SESSION_VERSION,
created_at: Utc::now(),
scan_paths,
settings,
groups,
user_selections: BTreeSet::new(),
group_index: 0,
file_index: 0,
}
}
#[must_use]
pub fn to_results(&self) -> (Vec<DuplicateGroup>, ScanSummary) {
let groups: Vec<DuplicateGroup> = self.groups.iter().cloned().map(Into::into).collect();
let summary = ScanSummary {
duplicate_groups: groups.len(),
duplicate_files: groups.iter().map(|g| g.duplicate_count()).sum(),
reclaimable_space: groups.iter().map(|g| g.wasted_space()).sum(),
total_files: groups.iter().map(|g| g.files.len()).sum(),
total_size: groups
.iter()
.map(|g| g.files.iter().map(|f| f.size).sum::<u64>())
.sum(),
..ScanSummary::default()
};
(groups, summary)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SessionSettings {
pub follow_symlinks: bool,
pub skip_hidden: bool,
pub min_size: Option<u64>,
pub max_size: Option<u64>,
pub newer_than: Option<DateTime<Utc>>,
pub older_than: Option<DateTime<Utc>>,
pub ignore_patterns: Vec<String>,
pub regex_include: Vec<String>,
pub regex_exclude: Vec<String>,
pub file_categories: Vec<crate::scanner::FileCategory>,
pub io_threads: usize,
pub paranoid: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionGroup {
pub id: usize,
pub hash: [u8; 32],
pub size: u64,
pub files: Vec<crate::scanner::FileEntry>,
#[serde(default)]
pub reference_paths: Vec<PathBuf>,
}
impl SessionGroup {
#[must_use]
pub fn from_duplicate_group(group: &DuplicateGroup, id: usize) -> Self {
Self {
id,
hash: group.hash,
size: group.size,
files: group.files.clone(),
reference_paths: group.reference_paths.clone(),
}
}
}
impl From<SessionGroup> for DuplicateGroup {
fn from(sg: SessionGroup) -> Self {
DuplicateGroup::new(sg.hash, sg.size, sg.files, sg.reference_paths)
}
}