use std::path::PathBuf;
use std::sync::Arc;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::mount::{Mount, MountId, MountManager, MountMeta, MountSource};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(missing_docs)]
pub struct MountInfo {
pub id: String,
pub name: String,
pub paths: Vec<String>,
pub auto_description: String,
pub auto_meta: MountMeta,
pub source: String,
pub enrichment_pending: bool,
pub last_enriched_at: Option<String>,
pub created_at: String,
pub updated_at: String,
pub last_active_at: String,
}
impl From<&Mount> for MountInfo {
fn from(m: &Mount) -> Self {
Self {
id: m.id.to_string(),
name: m.name.clone(),
paths: m
.paths
.iter()
.map(|p| p.to_string_lossy().to_string())
.collect(),
auto_description: m.auto_description.clone(),
auto_meta: m.auto_meta.clone(),
source: m.source.to_string(),
enrichment_pending: m.enrichment_pending,
last_enriched_at: m.last_enriched_at.map(|t| t.to_rfc3339()),
created_at: m.created_at.to_rfc3339(),
updated_at: m.updated_at.to_rfc3339(),
last_active_at: m.last_active_at.to_rfc3339(),
}
}
}
#[allow(dead_code)]
pub struct MountApi {
pub(crate) mount_manager: Arc<MountManager>,
}
impl MountApi {
pub fn new(mount_manager: Arc<MountManager>) -> Self {
Self { mount_manager }
}
pub fn list_mounts(&self) -> Vec<MountInfo> {
self.mount_manager
.list_mounts()
.iter()
.map(MountInfo::from)
.collect()
}
pub fn get_mount(&self, id: &str) -> Option<MountInfo> {
let mount_id: MountId = Uuid::parse_str(id).ok()?;
self.mount_manager
.get_mount(mount_id)
.as_ref()
.map(MountInfo::from)
}
pub fn get_mount_by_name(&self, name: &str) -> Option<MountInfo> {
self.mount_manager
.get_mount_by_name(name)
.as_ref()
.map(MountInfo::from)
}
pub fn resolve_mounts(&self, mount_ids: &[MountId]) -> Vec<Mount> {
self.mount_manager.get_mounts_ordered(mount_ids)
}
pub fn create_mount(&self, name: String, paths: Vec<String>) -> Result<MountInfo> {
let paths: Vec<PathBuf> = paths.into_iter().map(PathBuf::from).collect();
let mount = self
.mount_manager
.create_mount(name, paths, MountSource::Manual)?;
Ok(MountInfo::from(&mount))
}
pub fn update_enrichment(
&self,
id: &str,
auto_description: Option<String>,
auto_meta: Option<MountMeta>,
) -> Result<MountInfo> {
let mount_id: MountId = Uuid::parse_str(id).context("Invalid mount ID")?;
let mount = self
.mount_manager
.update_enrichment(mount_id, auto_description, auto_meta)?;
Ok(MountInfo::from(&mount))
}
pub fn rename_mount(&self, id: &str, new_name: String) -> Result<MountInfo> {
let mount_id: MountId = Uuid::parse_str(id).context("Invalid mount ID")?;
let mount = self.mount_manager.rename(mount_id, new_name)?;
Ok(MountInfo::from(&mount))
}
pub fn remove_mount(&self, id: &str) -> Result<()> {
let mount_id: MountId = Uuid::parse_str(id).context("Invalid mount ID")?;
self.mount_manager.remove_mount(mount_id)
}
pub fn touch_mount(&self, id: &str) {
if let Ok(mount_id) = Uuid::parse_str(id) {
self.mount_manager.touch(mount_id);
}
}
pub fn rescan(&self, id: &str) -> Result<MountInfo> {
let mount_id: MountId = Uuid::parse_str(id).context("Invalid mount ID")?;
self.mount_manager
.seed_auto_meta(mount_id)
.context("Failed to rescan mount")?;
self.get_mount(id)
.ok_or_else(|| anyhow::anyhow!("Mount not found after rescan"))
}
pub fn detect(&self, message: &str) -> Option<MountInfo> {
use crate::mount::DetectionResult;
match self.mount_manager.detect(message) {
DetectionResult::Found(id) => self
.mount_manager
.get_mount(id)
.as_ref()
.map(MountInfo::from),
DetectionResult::NoMatch { .. } => None,
}
}
}