99 lines
2.7 KiB
Rust
99 lines
2.7 KiB
Rust
use cap_std::fs::Dir;
|
|
use std::io::{Read, Result as IoResult, Write};
|
|
|
|
mod traits;
|
|
pub use traits::{Event, FlowData};
|
|
|
|
mod lock;
|
|
use lock::RepoLock;
|
|
|
|
mod changelist;
|
|
pub use changelist::ChangeList;
|
|
|
|
mod thin_snapshot;
|
|
pub use thin_snapshot::ThinSnapshot;
|
|
|
|
pub struct Repository(pub Dir);
|
|
|
|
impl Repository {
|
|
fn subdir(&self, sd: &str) -> IoResult<Dir> {
|
|
let _ = self.0.create_dir(sd);
|
|
self.0.open_dir(sd)
|
|
}
|
|
pub fn changes(&self) -> IoResult<Changes> {
|
|
self.subdir("changes").map(Changes)
|
|
}
|
|
pub fn snapshots(&self) -> IoResult<Snapshots> {
|
|
self.subdir("snapshots").map(Snapshots)
|
|
}
|
|
}
|
|
|
|
pub type ChangeHash = [u8; 32];
|
|
pub struct Changes(Dir);
|
|
|
|
fn yzb64_file_name(h: &ChangeHash) -> [u8; 43] {
|
|
let mut buf = [0u8; 43];
|
|
assert_eq!(
|
|
yzb64::base64::encode_engine_slice(h, &mut buf, &*yzb64::B64_ENGINE),
|
|
43
|
|
);
|
|
buf
|
|
}
|
|
|
|
impl Changes {
|
|
pub fn insert(&self, h: &ChangeHash, contents: &[u8]) -> IoResult<bool> {
|
|
let buf = yzb64_file_name(h);
|
|
let buf = std::str::from_utf8(&buf).unwrap();
|
|
let _l = RepoLock::lock_write(&self.0, ".lock");
|
|
if self.0.exists(buf) {
|
|
return Ok(false);
|
|
}
|
|
let mut ecd = zstd::stream::write::Encoder::new(self.0.create(buf)?, 5)?;
|
|
ecd.write_all(contents)?;
|
|
ecd.finish()?;
|
|
Ok(true)
|
|
}
|
|
|
|
pub fn remove(&self, h: &ChangeHash) -> IoResult<()> {
|
|
let buf = yzb64_file_name(h);
|
|
let buf = std::str::from_utf8(&buf).unwrap();
|
|
let _l = RepoLock::lock_write(&self.0, ".lock");
|
|
self.0.remove_file(buf)
|
|
}
|
|
|
|
pub fn get(&self, h: &ChangeHash) -> IoResult<Vec<u8>> {
|
|
let buf = yzb64_file_name(h);
|
|
let buf = std::str::from_utf8(&buf).unwrap();
|
|
let _l = RepoLock::lock_read(&self.0, ".lock");
|
|
let mut dcd = zstd::stream::read::Decoder::new(self.0.open(buf)?)?;
|
|
let mut buf2 = Vec::new();
|
|
dcd.read_to_end(&mut buf2)?;
|
|
Ok(buf2)
|
|
}
|
|
}
|
|
|
|
pub struct Snapshots(Dir);
|
|
|
|
impl Snapshots {
|
|
pub fn insert_thin(&self, name: &str, contents: &ThinSnapshot) -> IoResult<bool> {
|
|
let _l = RepoLock::lock_write(&self.0, ".lock");
|
|
if self.0.exists(name) {
|
|
return Ok(false);
|
|
}
|
|
let f = self.0.create(name)?;
|
|
contents.write_to_stream(f)?;
|
|
Ok(true)
|
|
}
|
|
|
|
pub fn remove(&self, name: &str) -> IoResult<()> {
|
|
let _l = RepoLock::lock_write(&self.0, ".lock");
|
|
self.0.remove_file(name)
|
|
}
|
|
|
|
pub fn get_thin(&self, name: &str) -> IoResult<ThinSnapshot> {
|
|
let _l = RepoLock::lock_read(&self.0, ".lock");
|
|
let f = self.0.open(name)?;
|
|
ThinSnapshot::read_from_stream(f)
|
|
}
|
|
}
|