WIP
This commit is contained in:
145
libbsv/src/simple_db/db.rs
Normal file
145
libbsv/src/simple_db/db.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
// This file is part of bsv.
|
||||
//
|
||||
// bsv is free software: you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, either version 3 of the License, or (at your option)
|
||||
// any later version.
|
||||
//
|
||||
// cdb is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
// more details.
|
||||
//
|
||||
// You should have received a copy of the Affero GNU General Public License
|
||||
// along with cdb. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
extern crate tempfile;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io::{Read, Seek};
|
||||
use std::fs::{File, OpenOptions, create_dir, create_dir_all};
|
||||
|
||||
use tempfile::{NamedTempFile};
|
||||
|
||||
use crate::core::error::*;
|
||||
use crate::core::ObjectId;
|
||||
use crate::core::{ObjectType, OTYPE_BLOB};
|
||||
|
||||
use super::object::{
|
||||
ObjectReader, WriteAsObject,
|
||||
};
|
||||
|
||||
|
||||
const OBJECTS_DIR: &str = "objects";
|
||||
const TMP_DIR: &str = "tmp";
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SimpleDb {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
|
||||
impl SimpleDb {
|
||||
pub fn new(path: &Path) -> Result<SimpleDb> {
|
||||
Ok(SimpleDb {
|
||||
path: path.into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
pub fn setup(&self) -> Result<()> {
|
||||
create_dir(self.objects_dir())?;
|
||||
create_dir(self.tmp_dir())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn has_object(&self, oid: &ObjectId) -> bool {
|
||||
let obj_path = self.path_from_id(oid);
|
||||
if let Ok(metadata) = std::fs::metadata(obj_path) {
|
||||
metadata.is_file()
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store_object<R: Read + Seek>(&self, otype: &ObjectType, mut reader: R)
|
||||
-> Result<ObjectId> {
|
||||
let mut tmp_file = self.create_tmp_file()?;
|
||||
let oid = reader.write_as_object(&mut tmp_file, otype)?;
|
||||
let dst_file_path = self.path_from_id(&oid);
|
||||
|
||||
// TODO: Check if dst_file_path exists
|
||||
|
||||
create_dir_all(dst_file_path.parent().unwrap())?;
|
||||
match tmp_file.persist(dst_file_path) {
|
||||
Ok(file) => {
|
||||
file.sync_data()?;
|
||||
Ok(oid)
|
||||
},
|
||||
Err(err) => Err(err.error.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store_file_as_blob(&self, file_path: &Path) -> Result<ObjectId> {
|
||||
let file = OpenOptions::new().read(true).open(file_path)?;
|
||||
self.store_object(OTYPE_BLOB, file)
|
||||
}
|
||||
|
||||
pub fn read_object(&self, oid: &ObjectId) -> Result<ObjectReader<File>> {
|
||||
let path = self.path_from_id(oid);
|
||||
let file = OpenOptions::new().read(true).open(path)?;
|
||||
ObjectReader::new(file)
|
||||
}
|
||||
|
||||
fn objects_dir(&self) -> PathBuf {
|
||||
let mut path = self.path.clone();
|
||||
path.push(OBJECTS_DIR);
|
||||
path
|
||||
}
|
||||
|
||||
fn tmp_dir(&self) -> PathBuf {
|
||||
let mut path = self.path.clone();
|
||||
path.push(TMP_DIR);
|
||||
path
|
||||
}
|
||||
|
||||
fn path_from_id(&self, oid: &ObjectId) -> PathBuf {
|
||||
let oid_str = oid.to_string();
|
||||
let mut path = self.path.clone();
|
||||
|
||||
path.push(OBJECTS_DIR);
|
||||
path.push(oid_str.get(..4).unwrap()); // unwrap is ok here because we know oid_str is a
|
||||
path.push(oid_str.get(4..).unwrap()); // hexadecimal number (i.e. ascii only).
|
||||
|
||||
path
|
||||
}
|
||||
|
||||
fn create_tmp_file(&self) -> Result<NamedTempFile> {
|
||||
let tmp_dir = self.tmp_dir();
|
||||
|
||||
Ok(tempfile::Builder::new().tempfile_in(tmp_dir)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::{FromStr};
|
||||
|
||||
use super::ObjectId;
|
||||
use super::SimpleDb;
|
||||
|
||||
#[test]
|
||||
fn simple_db_path_from_id() {
|
||||
let db = SimpleDb::new(std::path::Path::new(".bsv")).unwrap();
|
||||
let oid = ObjectId::from_str("0001020304050607").unwrap();
|
||||
|
||||
let path = db.path_from_id(&oid);
|
||||
assert_eq!(path, std::path::PathBuf::from(".bsv/objects/0001/020304050607"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user