use std::fs;
use std::path::Path;
use std::path::PathBuf;
use crate::error::{Result, StorageError};
mod index;
mod lifecycle;
mod ocr;
mod paths;
pub mod types;
pub use types::{
default_ocr_annotations, AttachmentManifest, AttachmentManifestEntry, ContextWindow,
MessageAttachment, OcrAnnotationEntry, OcrAnnotations, OcrModelAnnotation, OcrRegion,
SideChatData, SideChatMetadata, ThreadData, ThreadMessage, ThreadMetadata, WorkspaceMetadata,
DEFAULT_SIDE_CHAT_TITLE, DEFAULT_THREAD_TITLE, EMPTY_STATE_ASSET_ID,
};
pub(crate) fn atomic_write(path: &Path, contents: &[u8]) -> Result<()> {
let file_name = path
.file_name()
.and_then(|value| value.to_str())
.unwrap_or("data");
let temporary = path.with_file_name(format!(".{file_name}.tmp-{}", uuid::Uuid::new_v4()));
fs::write(&temporary, contents)?;
fs::rename(temporary, path)?;
Ok(())
}
pub struct ThreadStorage {
pub(crate) base_dir: PathBuf,
pub(crate) objects_dir: PathBuf,
pub(crate) index_path: PathBuf,
}
impl ThreadStorage {
pub fn with_config_root(config_root: PathBuf) -> Result<Self> {
let base_dir = config_root.join("threads");
let objects_dir = config_root.join("objects");
let index_path = base_dir.join("index.json");
fs::create_dir_all(&base_dir)?;
fs::create_dir_all(&objects_dir)?;
Ok(Self {
base_dir,
objects_dir,
index_path,
})
}
pub fn new() -> Result<Self> {
let config_root = crate::paths::base_config_dir().ok_or(StorageError::NoDataDir)?;
Self::with_config_root(config_root)
}
pub fn base_dir(&self) -> &PathBuf {
&self.base_dir
}
pub fn objects_dir(&self) -> &PathBuf {
&self.objects_dir
}
pub(super) fn thread_dir(&self, thread_id: &str) -> PathBuf {
self.base_dir.join(thread_id)
}
}