squigit_storage/threads/
mod.rs1use std::fs;
7use std::path::Path;
8use std::path::PathBuf;
9
10use crate::error::{Result, StorageError};
11
12mod index;
13mod lifecycle;
14mod ocr;
15mod paths;
16pub mod types;
17
18pub use types::{
19 default_ocr_annotations, AttachmentManifest, AttachmentManifestEntry, ContextWindow,
20 MessageAttachment, OcrAnnotationEntry, OcrAnnotations, OcrModelAnnotation, OcrRegion,
21 SideChatData, SideChatMetadata, ThreadData, ThreadMessage, ThreadMetadata, WorkspaceMetadata,
22 DEFAULT_SIDE_CHAT_TITLE, DEFAULT_THREAD_TITLE, EMPTY_STATE_ASSET_ID,
23};
24
25pub(crate) fn atomic_write(path: &Path, contents: &[u8]) -> Result<()> {
26 let file_name = path
27 .file_name()
28 .and_then(|value| value.to_str())
29 .unwrap_or("data");
30 let temporary = path.with_file_name(format!(".{file_name}.tmp-{}", uuid::Uuid::new_v4()));
31 fs::write(&temporary, contents)?;
32 fs::rename(temporary, path)?;
33 Ok(())
34}
35
36pub struct ThreadStorage {
38 pub(crate) base_dir: PathBuf,
40 pub(crate) objects_dir: PathBuf,
42 pub(crate) index_path: PathBuf,
44}
45
46impl ThreadStorage {
47 pub fn with_config_root(config_root: PathBuf) -> Result<Self> {
48 let base_dir = config_root.join("threads");
49 let objects_dir = config_root.join("objects");
50 let index_path = base_dir.join("index.json");
51 fs::create_dir_all(&base_dir)?;
52 fs::create_dir_all(&objects_dir)?;
53 Ok(Self {
54 base_dir,
55 objects_dir,
56 index_path,
57 })
58 }
59
60 pub fn new() -> Result<Self> {
62 let config_root = crate::paths::base_config_dir().ok_or(StorageError::NoDataDir)?;
63 Self::with_config_root(config_root)
64 }
65
66 pub fn base_dir(&self) -> &PathBuf {
68 &self.base_dir
69 }
70
71 pub fn objects_dir(&self) -> &PathBuf {
73 &self.objects_dir
74 }
75
76 pub(super) fn thread_dir(&self, thread_id: &str) -> PathBuf {
77 self.base_dir.join(thread_id)
78 }
79}