use std::path::{Path, PathBuf};
use automerge::{AutoCommit, ObjType, ReadDoc, ROOT, transaction::Transactable};
use crate::error::{Result, WeaveError};
pub struct EntityStateDoc {
pub(crate) doc: AutoCommit,
pub(crate) path: PathBuf,
}
impl EntityStateDoc {
pub fn open(path: &Path) -> Result<Self> {
let doc = if path.exists() {
let data = std::fs::read(path)?;
AutoCommit::load(&data)?
} else {
let mut doc = AutoCommit::new();
doc.put_object(ROOT, "entities", ObjType::Map)?;
doc.put_object(ROOT, "agents", ObjType::Map)?;
doc.put_object(ROOT, "operations", ObjType::List)?;
doc
};
Ok(Self {
doc,
path: path.to_path_buf(),
})
}
pub fn new_memory() -> Result<Self> {
let mut doc = AutoCommit::new();
doc.put_object(ROOT, "entities", ObjType::Map)?;
doc.put_object(ROOT, "agents", ObjType::Map)?;
doc.put_object(ROOT, "operations", ObjType::List)?;
Ok(Self {
doc,
path: PathBuf::new(),
})
}
pub fn save(&mut self) -> Result<()> {
if self.path.as_os_str().is_empty() {
return Ok(()); }
if let Some(parent) = self.path.parent() {
std::fs::create_dir_all(parent)?;
}
let data = self.doc.save();
std::fs::write(&self.path, data)?;
Ok(())
}
pub(crate) fn entities_id(&self) -> Result<automerge::ObjId> {
match self.doc.get(ROOT, "entities")? {
Some((_, id)) => Ok(id),
None => Err(WeaveError::Automerge(
automerge::AutomergeError::InvalidObjId("entities map missing".into()),
)),
}
}
pub(crate) fn agents_id(&self) -> Result<automerge::ObjId> {
match self.doc.get(ROOT, "agents")? {
Some((_, id)) => Ok(id),
None => Err(WeaveError::Automerge(
automerge::AutomergeError::InvalidObjId("agents map missing".into()),
)),
}
}
pub(crate) fn operations_id(&self) -> Result<automerge::ObjId> {
match self.doc.get(ROOT, "operations")? {
Some((_, id)) => Ok(id),
None => Err(WeaveError::Automerge(
automerge::AutomergeError::InvalidObjId("operations list missing".into()),
)),
}
}
}
pub fn now_ms() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}