#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SourceState {
Active,
Preparing,
NeedsUpdate,
Paused,
FolderNotFound,
PermissionProblem,
Removed,
}
impl SourceState {
pub fn user_label(self) -> &'static str {
match self {
SourceState::Active => "Ready",
SourceState::Preparing => "Preparing",
SourceState::NeedsUpdate => "Needs update",
SourceState::Paused => "Paused",
SourceState::FolderNotFound => "Folder not found",
SourceState::PermissionProblem => "Cannot open",
SourceState::Removed => "Removed",
}
}
pub fn is_searchable(self) -> bool {
matches!(
self,
SourceState::Active | SourceState::NeedsUpdate | SourceState::Preparing
)
}
pub fn can_refresh(self) -> bool {
matches!(
self,
SourceState::Active
| SourceState::NeedsUpdate
| SourceState::FolderNotFound
| SourceState::PermissionProblem
)
}
pub fn as_str(self) -> &'static str {
match self {
SourceState::Active => "active",
SourceState::Preparing => "preparing",
SourceState::NeedsUpdate => "needs_update",
SourceState::Paused => "paused",
SourceState::FolderNotFound => "missing",
SourceState::PermissionProblem => "permission_denied",
SourceState::Removed => "removed",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FileState {
Discovered,
Preparing,
Ready,
NeedsUpdate,
PartlyPrepared,
CouldNotPrepare,
FileNotFound,
Ignored,
}
impl FileState {
pub fn user_label(self) -> &'static str {
match self {
FileState::Discovered => "Waiting",
FileState::Preparing => "Preparing",
FileState::Ready => "Ready",
FileState::NeedsUpdate => "Needs update",
FileState::PartlyPrepared => "Partly prepared",
FileState::CouldNotPrepare => "Could not prepare",
FileState::FileNotFound => "File not found",
FileState::Ignored => "Skipped",
}
}
pub fn from_catalog_status(s: &str) -> Self {
match s {
"discovered" => FileState::Discovered,
"indexed" => FileState::Ready,
"stale" => FileState::NeedsUpdate,
"missing" | "deleted" => FileState::FileNotFound,
"permission_denied" => FileState::CouldNotPrepare,
"unsupported" => FileState::Ignored,
"failed" => FileState::PartlyPrepared,
_ => FileState::Discovered,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FileFingerprint {
pub size_bytes: u64,
pub modified_at: Option<String>,
pub content_hash: Option<String>,
}
impl FileFingerprint {
pub fn from_metadata(meta: &std::fs::Metadata) -> Self {
use std::time::UNIX_EPOCH;
let modified_at = meta.modified().ok().and_then(|t| {
t.duration_since(UNIX_EPOCH)
.ok()
.map(|d| format!("{}", d.as_secs()))
});
Self {
size_bytes: meta.len(),
modified_at,
content_hash: None,
}
}
pub fn metadata_changed(&self, other: &FileFingerprint) -> bool {
self.size_bytes != other.size_bytes || self.modified_at != other.modified_at
}
}
#[derive(Debug, Clone)]
pub struct SourceCheckResult {
pub source_state: SourceState,
pub files_changed: u64,
pub files_missing: u64,
pub files_new: u64,
}
pub fn check_source_path(path: &std::path::Path) -> SourceState {
match std::fs::metadata(path) {
Ok(meta) if meta.is_dir() => SourceState::Active,
Ok(_) => SourceState::Active, Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
SourceState::PermissionProblem
}
Err(_) => SourceState::FolderNotFound,
}
}