Graphite/desktop/src/persist.rs

93 lines
2.8 KiB
Rust

use crate::wrapper::messages::{DocumentId, PersistedState};
pub(crate) fn read_state() -> PersistedState {
let path = state_file_path();
let data = match std::fs::read_to_string(&path) {
Ok(d) => d,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
tracing::info!("No persistent data file found at {path:?}, starting fresh");
return PersistedState::default();
}
Err(e) => {
tracing::error!("Failed to read persistent data from disk: {e}");
return PersistedState::default();
}
};
let loaded = match ron::from_str(&data) {
Ok(d) => d,
Err(e) => {
tracing::error!("Failed to deserialize persistent data: {e}");
return PersistedState::default();
}
};
garbage_collect_document_files(&loaded);
loaded
}
pub(crate) fn write_state(state: PersistedState) {
let state: &PersistedState = &state;
let data = match ron::ser::to_string_pretty(state, Default::default()) {
Ok(d) => d,
Err(e) => {
tracing::error!("Failed to serialize persistent data: {e}");
return;
}
};
if let Err(e) = std::fs::write(state_file_path(), data) {
tracing::error!("Failed to write persistent data to disk: {e}");
}
garbage_collect_document_files(&state);
}
pub(crate) fn write_document_content(id: DocumentId, document_content: String) {
if let Err(e) = std::fs::write(document_content_path(&id), document_content) {
tracing::error!("Failed to write document {id:?} to disk: {e}");
}
}
pub(crate) fn read_document_content(id: &DocumentId) -> Option<String> {
std::fs::read_to_string(document_content_path(id)).ok()
}
pub(crate) fn delete_document(id: &DocumentId) {
if let Err(e) = std::fs::remove_file(document_content_path(id)) {
tracing::error!("Failed to delete document {id:?} from disk: {e}");
}
}
fn garbage_collect_document_files(state: &PersistedState) {
let valid_paths: std::collections::HashSet<_> = state.documents.iter().map(|doc| document_content_path(&doc.id)).collect();
let directory = crate::dirs::app_autosave_documents_dir();
let entries = match std::fs::read_dir(&directory) {
Ok(entries) => entries,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return,
Err(e) => {
tracing::error!("Failed to read autosave documents directory: {e}");
return;
}
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_file() && !valid_paths.contains(&path) {
if let Err(e) = std::fs::remove_file(&path) {
tracing::error!("Failed to remove orphaned document file {path:?}: {e}");
}
}
}
}
fn state_file_path() -> std::path::PathBuf {
let mut path = crate::dirs::app_data_dir();
path.push(crate::consts::APP_STATE_FILE_NAME);
path
}
fn document_content_path(id: &DocumentId) -> std::path::PathBuf {
let mut path = crate::dirs::app_autosave_documents_dir();
path.push(format!("{:x}.{}", id.0, graphite_desktop_wrapper::FILE_EXTENSION));
path
}