summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/error.rs16
-rw-r--r--src/lib.rs66
2 files changed, 74 insertions, 8 deletions
diff --git a/src/error.rs b/src/error.rs
index c6b19db..b84f5eb 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -21,7 +21,7 @@ pub enum Error {
/// A library usage error.
LibraryError(LibraryError),
/// An error that occurred due to a poisoned lock.
- PoisonError,
+ PoisonError(sync::PoisonError<sync::MutexGuard<'static, crate::Manager>>),
/// An error that occurred during random number generation.
RandError(Box<dyn error::Error>),
/// An error that is caused by an unexpected value returned by libnitrokey.
@@ -70,14 +70,14 @@ impl From<str::Utf8Error> for Error {
}
}
-impl<T> From<sync::PoisonError<T>> for Error {
- fn from(_error: sync::PoisonError<T>) -> Self {
- Error::PoisonError
+impl From<sync::PoisonError<sync::MutexGuard<'static, crate::Manager>>> for Error {
+ fn from(error: sync::PoisonError<sync::MutexGuard<'static, crate::Manager>>) -> Self {
+ Error::PoisonError(error)
}
}
-impl<T> From<sync::TryLockError<T>> for Error {
- fn from(error: sync::TryLockError<T>) -> Self {
+impl From<sync::TryLockError<sync::MutexGuard<'static, crate::Manager>>> for Error {
+ fn from(error: sync::TryLockError<sync::MutexGuard<'static, crate::Manager>>) -> Self {
match error {
sync::TryLockError::Poisoned(err) => err.into(),
sync::TryLockError::WouldBlock => Error::ConcurrentAccessError,
@@ -98,7 +98,7 @@ impl error::Error for Error {
Error::CommunicationError(ref err) => Some(err),
Error::ConcurrentAccessError => None,
Error::LibraryError(ref err) => Some(err),
- Error::PoisonError => None,
+ Error::PoisonError(ref err) => Some(err),
Error::RandError(ref err) => Some(err.as_ref()),
Error::UnexpectedError => None,
Error::UnknownError(_) => None,
@@ -114,7 +114,7 @@ impl fmt::Display for Error {
Error::CommunicationError(ref err) => write!(f, "Communication error: {}", err),
Error::ConcurrentAccessError => write!(f, "Internal error: concurrent access"),
Error::LibraryError(ref err) => write!(f, "Library error: {}", err),
- Error::PoisonError => write!(f, "Internal error: poisoned lock"),
+ Error::PoisonError(_) => write!(f, "Internal error: poisoned lock"),
Error::RandError(ref err) => write!(f, "RNG error: {}", err),
Error::UnexpectedError => write!(f, "An unexpected error occurred"),
Error::UnknownError(ref err) => write!(f, "Unknown error: {}", err),
diff --git a/src/lib.rs b/src/lib.rs
index c35829c..573f45f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -89,6 +89,9 @@
#![warn(missing_docs, rust_2018_compatibility, rust_2018_idioms, unused)]
+#[macro_use(lazy_static)]
+extern crate lazy_static;
+
mod auth;
mod config;
mod device;
@@ -98,6 +101,8 @@ mod pws;
mod util;
use std::fmt;
+use std::marker;
+use std::sync;
use nitrokey_sys;
@@ -117,6 +122,10 @@ pub const DEFAULT_ADMIN_PIN: &str = "12345678";
/// The default user PIN for all Nitrokey devices.
pub const DEFAULT_USER_PIN: &str = "123456";
+lazy_static! {
+ static ref MANAGER: sync::Mutex<Manager> = sync::Mutex::new(Manager::new());
+}
+
/// A version of the libnitrokey library.
///
/// Use the [`get_library_version`](fn.get_library_version.html) function to query the library
@@ -147,6 +156,63 @@ impl fmt::Display for Version {
}
}
+/// A manager for connections to Nitrokey devices.
+///
+/// Currently, libnitrokey only provides access to one Nitrokey device at the same time. This
+/// manager struct makes sure that `nitrokey-rs` does not try to connect to two devices at the same
+/// time.
+///
+/// To obtain an instance of this manager, use the [`take`][] function.
+///
+/// [`take`]: fn.take.html
+#[derive(Debug)]
+pub struct Manager {
+ marker: marker::PhantomData<()>,
+}
+
+impl Manager {
+ fn new() -> Self {
+ Manager {
+ marker: marker::PhantomData,
+ }
+ }
+}
+
+/// Take an instance of the connection manager, blocking until an instance is available.
+///
+/// There may only be one [`Manager`][] instance at the same time. If there already is an
+/// instance, this method blocks. If you want a non-blocking version, use [`take`][].
+///
+/// # Errors
+///
+/// - [`PoisonError`][] if the lock is poisoned
+///
+/// [`take`]: fn.take.html
+/// [`PoisonError`]: struct.Error.html#variant.PoisonError
+/// [`Manager`]: struct.Manager.html
+pub fn take_blocking() -> Result<sync::MutexGuard<'static, Manager>, Error> {
+ MANAGER.lock().map_err(Into::into)
+}
+
+/// Try to take an instance of the connection manager.
+///
+/// There may only be one [`Manager`][] instance at the same time. If there already is an
+/// instance, a [`ConcurrentAccessError`][] is returned. If you want a blocking version, use
+/// [`take_blocking`][].
+///
+/// # Errors
+///
+/// - [`ConcurrentAccessError`][] if the token for the `Manager` instance cannot be locked
+/// - [`PoisonError`][] if the lock is poisoned
+///
+/// [`take_blocking`]: fn.take_blocking.html
+/// [`ConcurrentAccessError`]: struct.Error.html#variant.ConcurrentAccessError
+/// [`PoisonError`]: struct.Error.html#variant.PoisonError
+/// [`Manager`]: struct.Manager.html
+pub fn take() -> Result<sync::MutexGuard<'static, Manager>, Error> {
+ MANAGER.try_lock().map_err(Into::into)
+}
+
/// Enables or disables debug output. Calling this method with `true` is equivalent to setting the
/// log level to `Debug`; calling it with `false` is equivalent to the log level `Error` (see
/// [`set_log_level`][]).