pub struct FsCertStorage {
dir: PathBuf,
}Fields§
§dir: PathBufImplementations§
Source§impl FsCertStorage
impl FsCertStorage
pub fn new(dir: impl Into<PathBuf>) -> Self
fn cert_dir(&self, id: &CertId) -> PathBuf
fn challenge_path(&self, domain: &str) -> PathBuf
fn lease_path(&self, id: &CertId) -> PathBuf
fn read_lease(&self, id: &CertId) -> Result<Option<LeaseFile>, AcmeError>
fn write_lease( &self, id: &CertId, owner: &str, ttl: Duration, ) -> Result<(), AcmeError>
Sourcefn create_lease_file(
&self,
id: &CertId,
owner: &str,
ttl: Duration,
) -> Result<()>
fn create_lease_file( &self, id: &CertId, owner: &str, ttl: Duration, ) -> Result<()>
Creates the lease file iff it does not already exist, and never
exposes a partially-written lease at lease_path: the full JSON is
written to a private, unique temp file first, then published with
hard_link, which — unlike creating the destination directly — fails
atomically with AlreadyExists when the destination is already there
(POSIX link(2), NTFS CreateHardLink) without ever making an empty
or partial file visible at lease_path. The OS guarantees exactly one
concurrent caller’s hard_link wins.
Falls back to the old create_new + write_all path only when
hard_link itself errors with something other than AlreadyExists
(e.g. unsupported on some network filesystem). That fallback has a
reduced guarantee: the destination is briefly visible empty before the
content lands, since content can no longer be written before the path
is public.
Sourcefn take_over_expired_lease(
&self,
id: &CertId,
owner: &str,
ttl: Duration,
) -> Result<bool, AcmeError>
fn take_over_expired_lease( &self, id: &CertId, owner: &str, ttl: Duration, ) -> Result<bool, AcmeError>
Takes over a lease that read as expired (or corrupt), atomically with respect to every other contender.
The naive remove_opt + create_lease_file lets two contenders both
win (A removes and creates; B, already past its own read, removes A’s
fresh lease and creates its own). Moving the stale file aside with
rename and creating in its place does not fix it either: between the
rename and the create the lease path is empty, and a contender that
reaches its own exclusive create in that window wins alongside the one
doing the takeover.
So the takeover holds a separate mutex — an exclusively created
<lease>.takeover marker, the one primitive the filesystem does give
atomically — and installs the new lease by rename-over (via
atomic_write), which replaces the file without the path ever being
empty. Contenders that lose the marker concede for this round and
re-evaluate on their next pass.
Trait Implementations§
Source§impl CertStorage for FsCertStorage
impl CertStorage for FsCertStorage
Source§fn label(&self) -> String
fn label(&self) -> String
filesystem, store:<name>).fn load_account<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn save_account<'life0, 'life1, 'async_trait>(
&'life0 self,
creds: &'life1 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn load_cert<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 CertId,
) -> Pin<Box<dyn Future<Output = Result<Option<StoredCert>, AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn save_cert<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 CertId,
cert: &'life2 StoredCert,
) -> Pin<Box<dyn Future<Output = Result<(), AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn put_challenge<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
domain: &'life1 str,
key_auth: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<(), AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn put_challenge<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
domain: &'life1 str,
key_auth: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<(), AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
key_auth for domain; expires after ttl.fn get_challenge<'life0, 'life1, 'async_trait>(
&'life0 self,
domain: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn remove_challenge<'life0, 'life1, 'async_trait>(
&'life0 self,
domain: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn try_acquire_lease<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 CertId,
owner: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn try_acquire_lease<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 CertId,
owner: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
true when this owner now holds the lease for id (fresh or already
its own); false when another live owner holds it.Source§fn renew_lease<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 CertId,
owner: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn renew_lease<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 CertId,
owner: &'life2 str,
ttl: Duration,
) -> Pin<Box<dyn Future<Output = Result<bool, AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
owner holds it.Source§fn release_lease<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 CertId,
owner: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn release_lease<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 CertId,
owner: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), AcmeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
owner holds it (a no-op otherwise).Auto Trait Implementations§
impl Freeze for FsCertStorage
impl RefUnwindSafe for FsCertStorage
impl Send for FsCertStorage
impl Sync for FsCertStorage
impl Unpin for FsCertStorage
impl UnsafeUnpin for FsCertStorage
impl UnwindSafe for FsCertStorage
Blanket Implementations§
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more