use super::BlockDBOptions;
use crate::error::Error;
use std::{io::SeekFrom, ops::Deref, path::PathBuf};
use tokio::{
fs::{try_exists, OpenOptions},
io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt},
};
#[derive(Debug)]
pub struct OptionsStore {
pub options: BlockDBOptions,
}
impl Deref for OptionsStore {
type Target = BlockDBOptions;
fn deref(&self) -> &Self::Target {
&self.options
}
}
impl OptionsStore {
async fn new(
options_file_path: PathBuf,
options: Option<BlockDBOptions>,
) -> Result<Self, Error> {
let options = options.unwrap_or_default();
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(&options_file_path)
.await?;
file.write_all(&serde_json::to_vec_pretty(&options)?)
.await?;
Ok(Self { options })
}
async fn load(
options_file_path: PathBuf,
new_options: Option<BlockDBOptions>,
) -> Result<Self, Error> {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(&options_file_path)
.await?;
let mut options = {
let mut buffer = vec![];
file.read_to_end(&mut buffer).await?;
serde_json::from_slice::<BlockDBOptions>(&buffer)?
};
if let Some(new_options) = new_options {
if new_options.chunk_size != options.chunk_size {
return Err(Error::InvalidOption(
"Cannot change Chunk Size after opening a BlockDB".into(),
));
}
options.max_file_size = new_options.max_file_size;
file.seek(SeekFrom::Start(0)).await?;
file.write_all(&serde_json::to_vec_pretty(&options)?)
.await?;
}
Ok(Self { options })
}
pub(crate) async fn open(
directory: PathBuf,
options: Option<BlockDBOptions>,
) -> Result<Self, Error> {
let options_file_path = directory.join("options.json");
if try_exists(&options_file_path).await? {
Self::load(options_file_path, options).await
} else {
Self::new(options_file_path, options).await
}
}
}