summaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorWiktor Kwapisiewicz <wiktor@metacode.biz>2021-03-26 14:30:09 +0100
committerWiktor Kwapisiewicz <wiktor@metacode.biz>2021-03-31 11:29:22 +0200
commit80cdf06912ce0217c8af77f9b02b4377095cb803 (patch)
tree575203e2c48e693e52b0ba5e36ac333a3c85c83f /ipc
parent4516d5b4c39a765583f9f2fe4bad54bbe70de0c9 (diff)
ipc: Incorporate sequoia-core crate as a core module.
- This moves all functionality from sequoia_core crate as an inner `core` module of the ipc crate. - The `core` module has to be public as other crates depend on `core::Context` either directly (store, ffi) or indirectly (store through ffi crate). - Remove the `core` crate completely.
Diffstat (limited to 'ipc')
-rw-r--r--ipc/Cargo.toml2
-rw-r--r--ipc/src/core.rs331
-rw-r--r--ipc/src/lib.rs2
3 files changed, 333 insertions, 2 deletions
diff --git a/ipc/Cargo.toml b/ipc/Cargo.toml
index fb9bbecd..c5e9e6ca 100644
--- a/ipc/Cargo.toml
+++ b/ipc/Cargo.toml
@@ -21,7 +21,6 @@ maintenance = { status = "actively-developed" }
[dependencies]
sequoia-openpgp = { path = "../openpgp", version = "1.0.0", default-features = false }
-sequoia-core = { path = "../core", version = "0.22" }
anyhow = "1.0.18"
buffered-reader = { path = "../buffered-reader", version = "1.0.0", default-features = false }
@@ -38,6 +37,7 @@ thiserror = "1.0.2"
tokio = { version = "0.2.19", features = ["rt-core", "rt-util", "tcp", "uds", "io-util", "macros"] }
tokio-util = { version = "0.3", features = ["compat"] }
socket2 = "0.3.16"
+dirs = "2.0"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.8", default-features = false, features = ["winsock2"] }
diff --git a/ipc/src/core.rs b/ipc/src/core.rs
new file mode 100644
index 00000000..06adc353
--- /dev/null
+++ b/ipc/src/core.rs
@@ -0,0 +1,331 @@
+//! Contexts and errors.
+//!
+//! Sequoia tries to be useful for a wide variety of applications.
+//! Therefore, we need you to provide a little information about the
+//! context you are using Sequoia in.
+//!
+//! # Examples
+//!
+//! A context with reasonable defaults can be created using
+//! `Context::new`:
+//!
+//! ```no_run
+//! # use sequoia_ipc::core::{Context, Result};
+//! # fn main() -> Result<()> {
+//! let c = Context::new();
+//! # Ok(())
+//! # }
+//! ```
+
+#![doc(html_favicon_url = "https://docs.sequoia-pgp.org/favicon.png")]
+#![doc(html_logo_url = "https://docs.sequoia-pgp.org/logo.svg")]
+#![warn(missing_docs)]
+
+use dirs;
+use tempfile;
+
+use std::io;
+use std::path::{Path, PathBuf};
+
+/// A `Context` for Sequoia.
+///
+/// # Examples
+///
+/// A context with reasonable defaults can be created using
+/// `Context::new`:
+///
+/// ```no_run
+/// # use sequoia_ipc::core::{Context, Result};
+/// # fn main() -> Result<()> {
+/// let c = Context::new()?;
+/// # Ok(())
+/// # }
+/// ```
+///
+/// A context can be configured using the builder pattern with
+/// `Context::configure`:
+///
+/// ```
+/// # use sequoia_ipc::core::{Context, IPCPolicy, Result};
+/// # fn main() -> Result<()> {
+/// let c = Context::configure()
+/// # .ephemeral()
+/// .ipc_policy(IPCPolicy::Robust)
+/// .build()?;
+/// # Ok(())
+/// # }
+/// ```
+pub struct Context {
+ home: PathBuf,
+ lib: PathBuf,
+ ipc_policy: IPCPolicy,
+ ephemeral: bool,
+ cleanup: bool,
+}
+
+impl Clone for Context {
+ fn clone(&self) -> Self {
+ Context {
+ home: self.home.clone(),
+ lib: self.lib.clone(),
+ ipc_policy: self.ipc_policy,
+ ephemeral: self.ephemeral,
+ cleanup: false, // Prevent cleanup.
+ }
+ }
+}
+
+impl Drop for Context {
+ fn drop(&mut self) {
+ use std::fs::remove_dir_all;
+
+ if self.ephemeral && self.cleanup {
+ let _ = remove_dir_all(&self.home);
+ }
+ }
+}
+
+/// Returns $PREXIX at compile-time, or a reasonable default prefix.
+fn prefix() -> PathBuf {
+ /* XXX: Windows support. */
+ PathBuf::from(option_env!("PREFIX").unwrap_or("/usr/local"))
+}
+
+impl Context {
+ /// Creates a Context with reasonable defaults.
+ pub fn new() -> Result<Self> {
+ Self::configure().build()
+ }
+
+ /// Creates a Context that can be configured.
+ ///
+ /// The configuration is seeded like in `Context::new`, but can be
+ /// modified. A configuration has to be finalized using
+ /// `.build()` in order to turn it into a Context.
+ pub fn configure() -> Config {
+ Config(Context {
+ home: PathBuf::from(""), // Defer computation of default.
+ lib: prefix().join("lib").join("sequoia"),
+ ipc_policy: IPCPolicy::Robust,
+ ephemeral: false,
+ cleanup: false,
+ })
+ }
+
+ /// Returns the directory containing shared state.
+ pub fn home(&self) -> &Path {
+ &self.home
+ }
+
+ /// Returns the directory containing backend servers.
+ pub fn lib(&self) -> &Path {
+ &self.lib
+ }
+
+ /// Returns the IPC policy.
+ pub fn ipc_policy(&self) -> &IPCPolicy {
+ &self.ipc_policy
+ }
+
+ /// Returns whether or not this is an ephemeral context.
+ pub fn ephemeral(&self) -> bool {
+ self.ephemeral
+ }
+}
+
+/// Represents a `Context` configuration.
+///
+/// A context can be configured using the builder pattern with
+/// `Context::configure`:
+///
+/// ```
+/// # use sequoia_ipc::core::{Context, IPCPolicy, Result};
+/// # fn main() -> Result<()> {
+/// let c = Context::configure()
+/// # .ephemeral()
+/// .ipc_policy(IPCPolicy::Robust)
+/// .build()?;
+/// # Ok(())
+/// # }
+/// ```
+///
+/// You can create ephemeral context that are useful for tests and
+/// one-shot programs:
+///
+/// ```
+/// # use sequoia_ipc::core::{Context, Result};
+/// # use std::path::Path;
+/// # fn main() -> Result<()> {
+/// let c = Context::configure().ephemeral().build()?;
+/// let ephemeral_home = c.home().to_path_buf();
+/// // Do some tests.
+/// drop(c);
+/// assert!(! ephemeral_home.exists());
+/// # Ok(())
+/// # }
+/// ```
+pub struct Config(Context);
+
+impl Config {
+ /// Finalizes the configuration and returns a `Context`.
+ pub fn build(self) -> Result<Context> {
+ let mut c = self.0;
+
+ // As a special case, we defer the computation of the default
+ // home, because env::home_dir() may fail.
+ let home_not_set = c.home == PathBuf::from("");
+
+ // If we have an ephemeral home, and home is not explicitly
+ // set, create a temporary directory. Ephemeral contexts can
+ // share home directories, e.g. client and server processes
+ // share one home.
+ if c.ephemeral && home_not_set {
+ let tmp = tempfile::Builder::new().prefix("sequoia").tempdir()?;
+ c.home = tmp.into_path();
+ c.cleanup = true;
+ } else {
+ if home_not_set {
+ c.home =
+ dirs::home_dir().ok_or(
+ anyhow::anyhow!("Failed to get users home directory"))?
+ .join(".sequoia");
+ }
+ }
+ Ok(c)
+ }
+
+ /// Sets the directory containing shared state.
+ pub fn home<P: AsRef<Path>>(mut self, home: P) -> Self {
+ self.set_home(home);
+ self
+ }
+
+ /// Sets the directory containing shared state.
+ pub fn set_home<P: AsRef<Path>>(&mut self, home: P) -> PathBuf {
+ ::std::mem::replace(&mut self.0.home, PathBuf::new().join(home))
+ }
+
+ /// Sets the directory containing backend servers.
+ pub fn lib<P: AsRef<Path>>(mut self, lib: P) -> Self {
+ self.set_lib(lib);
+ self
+ }
+
+ /// Sets the directory containing backend servers.
+ pub fn set_lib<P: AsRef<Path>>(&mut self, lib: P) -> PathBuf {
+ ::std::mem::replace(&mut self.0.lib, PathBuf::new().join(lib))
+ }
+
+ /// Sets the IPC policy.
+ pub fn ipc_policy(mut self, policy: IPCPolicy) -> Self {
+ self.set_ipc_policy(policy);
+ self
+ }
+
+ /// Sets the IPC policy.
+ pub fn set_ipc_policy(&mut self, policy: IPCPolicy) -> IPCPolicy {
+ ::std::mem::replace(&mut self.0.ipc_policy, policy)
+ }
+
+ /// Makes this context ephemeral.
+ pub fn ephemeral(mut self) -> Self {
+ self.set_ephemeral();
+ self
+ }
+
+ /// Makes this context ephemeral.
+ pub fn set_ephemeral(&mut self) -> bool {
+ ::std::mem::replace(&mut self.0.ephemeral, true)
+ }
+}
+
+/* Error handling. */
+
+/// Result type for Sequoia.
+pub type Result<T> = ::std::result::Result<T, anyhow::Error>;
+
+#[derive(thiserror::Error, Debug)]
+/// Errors for Sequoia.
+pub enum Error {
+ /// An `io::Error` occurred.
+ #[error("{0}")]
+ IoError(#[from] io::Error),
+}
+
+
+/* IPC policy. */
+
+/// IPC policy for Sequoia.
+///
+/// With this policy you can control how Sequoia starts background
+/// servers.
+#[derive(PartialEq, Debug, Copy, Clone)]
+pub enum IPCPolicy {
+ /// External background servers only.
+ ///
+ /// We will always use external background servers. If starting
+ /// one fails, the operation will fail.
+ ///
+ /// The advantage is that we never spawn a thread.
+ ///
+ /// The disadvantage is that we need to locate the background
+ /// server to start. If you are distribute Sequoia with your
+ /// application, make sure to include the binaries, and to
+ /// configure the Context so that `context.lib()` points to the
+ /// directory containing the binaries.
+ External,
+
+ /// Internal background servers only.
+ ///
+ /// We will always use internal background servers. It is very
+ /// unlikely that this fails.
+ ///
+ /// The advantage is that this method is very robust. If you
+ /// distribute Sequoia with your application, you do not need to
+ /// ship the binary, and it does not matter what `context.lib()`
+ /// points to. This is very robust and convenient.
+ ///
+ /// The disadvantage is that we spawn a thread in your
+ /// application. Threads may play badly with `fork(2)`, file
+ /// handles, and locks. If you are not doing anything fancy,
+ /// however, and only use fork-then-exec, you should be okay.
+ Internal,
+
+ /// Prefer external, fall back to internal.
+ ///
+ /// We will first try to use an external background server, but
+ /// fall back on an internal one should that fail.
+ ///
+ /// The advantage is that if Sequoia is properly set up to find
+ /// the background servers, we will use these and get the
+ /// advantages of that approach. Because we fail back on using an
+ /// internal server, we gain the robustness of that approach.
+ ///
+ /// The disadvantage is that we may or may not spawn a thread in
+ /// your application. If this is unacceptable in your
+ /// environment, use the `External` policy.
+ Robust,
+}
+
+impl<'a> From<&'a IPCPolicy> for u8 {
+ fn from(policy: &IPCPolicy) -> Self {
+ match policy {
+ &IPCPolicy::External => 0,
+ &IPCPolicy::Internal => 1,
+ &IPCPolicy::Robust => 2,
+ }
+ }
+}
+
+
+// XXX: TryFrom would be nice.
+impl From<u8> for IPCPolicy {
+ fn from(policy: u8) -> Self {
+ match policy {
+ 0 => IPCPolicy::External,
+ 1 => IPCPolicy::Internal,
+ 2 => IPCPolicy::Robust,
+ n => panic!("Bad IPC policy: {}", n),
+ }
+ }
+}
diff --git a/ipc/src/lib.rs b/ipc/src/lib.rs
index 3c06c6ad..dbc9f965 100644
--- a/ipc/src/lib.rs
+++ b/ipc/src/lib.rs
@@ -64,7 +64,6 @@ use std::process::{Command, Stdio};
use std::thread;
use sequoia_openpgp as openpgp;
-use sequoia_core as core;
#[macro_use] mod trace;
pub mod assuan;
@@ -72,6 +71,7 @@ pub mod gnupg;
mod keygrip;
pub use self::keygrip::Keygrip;
pub mod sexp;
+pub mod core;
#[cfg(test)]
mod tests;