Refactor context creation to a builder pattern

This mainly refactors context creation to use a builder pattern.  It
also adds a logdir option to this builder patter but doesn't yet use
this.
This commit is contained in:
Floris Bruynooghe
2019-11-06 17:17:44 +01:00
parent dacde72456
commit f8736895cd
6 changed files with 133 additions and 40 deletions

View File

@@ -24,7 +24,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
use deltachat::constants::DC_MSG_ID_LAST_SPECIAL;
use deltachat::contact::Contact;
use deltachat::context::Context;
use deltachat::context::{Context, ContextBuilder};
use deltachat::dc_tools::{
as_path, dc_strdup, to_opt_string_lossy, to_string_lossy, OsStrExt, StrExt,
};
@@ -248,22 +248,15 @@ pub unsafe extern "C" fn dc_open(
}
let ffi_context = &*context;
let rust_cb = move |_ctx: &Context, evt: Event| ffi_context.translate_cb(evt);
let ctx = if blobdir.is_null() || *blobdir == 0 {
Context::new(
Box::new(rust_cb),
ffi_context.os_name.clone(),
as_path(dbfile).to_path_buf(),
)
} else {
Context::with_blobdir(
Box::new(rust_cb),
ffi_context.os_name.clone(),
as_path(dbfile).to_path_buf(),
as_path(blobdir).to_path_buf(),
)
};
match ctx {
let mut builder = ContextBuilder::new(
Box::new(rust_cb),
ffi_context.os_name.clone(),
as_path(dbfile).to_path_buf(),
);
if !blobdir.is_null() && *blobdir != 0 {
builder = builder.blobdir(as_path(blobdir).to_path_buf());
}
match builder.create() {
Ok(ctx) => {
let mut inner_guard = ffi_context.inner.write().unwrap();
*inner_guard = Some(ctx);

View File

@@ -366,11 +366,12 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
println!("Error: Bad arguments, expected [db-name].");
return Err(format_err!("No db-name specified"));
}
let context = Context::new(
let context = ContextBuilder::new(
Box::new(receive_event),
"CLI".into(),
Path::new(&args[1]).to_path_buf(),
)?;
)
.create()?;
println!("Delta Chat Core is awaiting your commands.");

View File

@@ -39,8 +39,9 @@ fn main() {
let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite");
println!("creating database {:?}", dbfile);
let ctx =
Context::new(Box::new(cb), "FakeOs".into(), dbfile).expect("Failed to create context");
let ctx = ContextBuilder::new(Box::new(cb), "FakeOs".into(), dbfile)
.create()
.expect("Failed to create context");
let running = Arc::new(RwLock::new(true));
let info = ctx.get_info();
let duration = time::Duration::from_millis(4000);

View File

@@ -94,30 +94,92 @@ pub fn get_info() -> HashMap<&'static str, String> {
res
}
impl Context {
/// Creates new context.
pub fn new(cb: Box<ContextCallback>, os_name: String, dbfile: PathBuf) -> Result<Context> {
let mut blob_fname = OsString::new();
blob_fname.push(dbfile.file_name().unwrap_or_default());
/// Builder for [Context].
///
/// # Example
///
/// ```
/// use deltachat::context::ContextBuilder;
/// let dir = tempfile::tempdir().unwrap();
/// let dbfile = dir.path().join("my-context.db");
/// let ctx = ContextBuilder::new(Box::new(|_, _| 0), "AppName".into(), dbfile)
/// .blobdir(dir.path().join("my-context-blobs"))
/// .logdir(dir.path().join("my-context-logs"))
/// .create()
/// .unwrap();
/// assert_eq!(ctx.get_blobdir(), dir.path().join("my-context-blobs"));
/// ```
#[derive(DebugStub)]
pub struct ContextBuilder {
#[debug_stub = "Callback"]
cb: Box<ContextCallback>,
os_name: String,
dbfile: PathBuf,
blobdir: PathBuf,
logdir: PathBuf,
}
impl ContextBuilder {
pub fn new(cb: Box<ContextCallback>, os_name: String, dbfile: PathBuf) -> Self {
let db_fname = OsString::from(dbfile.file_name().unwrap_or(&OsString::from("dc-context")));
let mut blob_fname = db_fname.clone();
blob_fname.push("-blobs");
let blobdir = dbfile.with_file_name(blob_fname);
if !blobdir.exists() {
std::fs::create_dir_all(&blobdir)?;
let mut log_fname = db_fname.clone();
log_fname.push("-logs");
ContextBuilder {
cb,
os_name,
blobdir: dbfile.with_file_name(blob_fname),
logdir: dbfile.with_file_name(log_fname),
dbfile,
}
Context::with_blobdir(cb, os_name, dbfile, blobdir)
}
pub fn with_blobdir(
pub fn blobdir(mut self, path: PathBuf) -> Self {
self.blobdir = path;
self
}
pub fn logdir(mut self, path: PathBuf) -> Self {
self.logdir = path;
self
}
pub fn create(self) -> Result<Context> {
if !self.blobdir.exists() {
std::fs::create_dir_all(&self.blobdir)?;
}
if !self.logdir.exists() {
std::fs::create_dir_all(&self.logdir)?;
}
Context::new(
self.cb,
self.os_name,
self.dbfile,
self.blobdir,
self.logdir,
)
}
}
impl Context {
fn new(
cb: Box<ContextCallback>,
os_name: String,
dbfile: PathBuf,
blobdir: PathBuf,
logdir: PathBuf,
) -> Result<Context> {
ensure!(
blobdir.is_dir(),
"Blobdir does not exist: {}",
blobdir.display()
);
ensure!(
logdir.is_dir(),
"Logdir does not exist: {}",
logdir.display()
);
let ctx = Context {
blobdir,
dbfile,
@@ -526,7 +588,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
std::fs::write(&dbfile, b"123").unwrap();
let res = Context::new(Box::new(|_, _| 0), "FakeOs".into(), dbfile);
let res = ContextBuilder::new(Box::new(|_, _| 0), "FakeOs".into(), dbfile).create();
assert!(res.is_err());
}
@@ -541,7 +603,9 @@ mod tests {
fn test_blobdir_exists() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
Context::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile).unwrap();
ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.create()
.unwrap();
let blobdir = tmp.path().join("db.sqlite-blobs");
assert!(blobdir.is_dir());
}
@@ -552,7 +616,7 @@ mod tests {
let dbfile = tmp.path().join("db.sqlite");
let blobdir = tmp.path().join("db.sqlite-blobs");
std::fs::write(&blobdir, b"123").unwrap();
let res = Context::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile);
let res = ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile).create();
assert!(res.is_err());
}
@@ -562,7 +626,9 @@ mod tests {
let subdir = tmp.path().join("subdir");
let dbfile = subdir.join("db.sqlite");
let dbfile2 = dbfile.clone();
Context::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile).unwrap();
ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.create()
.unwrap();
assert!(subdir.is_dir());
assert!(dbfile2.is_file());
}
@@ -572,7 +638,9 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let blobdir = PathBuf::new();
let res = Context::with_blobdir(Box::new(|_, _| 0), "FakeOS".into(), dbfile, blobdir);
let res = ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.blobdir(blobdir)
.create();
assert!(res.is_err());
}
@@ -581,10 +649,36 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let blobdir = tmp.path().join("blobs");
let res = Context::with_blobdir(Box::new(|_, _| 0), "FakeOS".into(), dbfile, blobdir);
ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.blobdir(blobdir.clone())
.create()
.unwrap();
assert!(blobdir.is_dir());
}
#[test]
fn test_with_empty_logdir() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let logdir = PathBuf::new();
let res = ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.logdir(logdir)
.create();
assert!(res.is_err());
}
#[test]
fn test_with_logdir_not_exists() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let logdir = tmp.path().join("logs");
ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.logdir(logdir.clone())
.create()
.unwrap();
assert!(logdir.is_dir());
}
#[test]
fn no_crashes_on_context_deref() {
let t = dummy_context();

View File

@@ -7,7 +7,7 @@ use tempfile::{tempdir, TempDir};
use crate::config::Config;
use crate::constants::KeyType;
use crate::context::{Context, ContextCallback};
use crate::context::{Context, ContextBuilder, ContextCallback};
use crate::events::Event;
use crate::key;
@@ -33,7 +33,9 @@ pub fn test_context(callback: Option<Box<ContextCallback>>) -> TestContext {
Some(cb) => cb,
None => Box::new(|_, _| 0),
};
let ctx = Context::new(cb, "FakeOs".into(), dbfile).unwrap();
let ctx = ContextBuilder::new(cb, "FakeOs".into(), dbfile)
.create()
.unwrap();
TestContext { ctx: ctx, dir: dir }
}

View File

@@ -219,7 +219,9 @@ struct TestContext {
fn create_test_context() -> TestContext {
let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite");
let ctx = Context::new(Box::new(cb), "FakeOs".into(), dbfile).unwrap();
let ctx = ContextBuilder::new(Box::new(cb), "FakeOs".into(), dbfile)
.create()
.unwrap();
TestContext { ctx, dir }
}