1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use std::future::Future;
use std::pin::Pin;
use crate::error::RustAuthError;
pub type SecondaryStorageFuture<'a, T> =
Pin<Box<dyn Future<Output = Result<T, RustAuthError>> + Send + 'a>>;
/// Async key-value storage for plugin data that can live outside the primary database.
pub trait SecondaryStorage: Send + Sync + 'static {
fn get<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, Option<String>>;
/// `ttl_seconds == Some(0)` means the value is already expired: implementations
/// must remove any existing key and must not store `value` without expiry.
fn set<'a>(
&'a self,
key: &'a str,
value: String,
ttl_seconds: Option<u64>,
) -> SecondaryStorageFuture<'a, ()>;
/// Store `value` only when `key` is absent.
///
/// Returns `Ok(true)` when the key was created, or `Ok(false)` when it already existed.
/// `ttl_seconds == Some(0)` means the value is already expired: implementations must
/// not create or delete the key and must return `Ok(false)`.
fn set_if_not_exists<'a>(
&'a self,
key: &'a str,
value: String,
ttl_seconds: Option<u64>,
) -> SecondaryStorageFuture<'a, bool>;
fn delete<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, ()>;
/// Atomically remove and return the stored value when present.
fn take<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, Option<String>>;
/// Atomically replace the key only when the currently stored value matches
/// `expected`. `expected == None` means the key must be absent.
///
/// Implementations must perform the comparison and replacement as a single
/// backend operation. A `get` followed by `set` is not sufficient for
/// shared or multi-process storage because concurrent writers can lose
/// updates between the read and write.
///
/// Returns `Ok(true)` when the replacement was applied.
fn compare_and_set<'a>(
&'a self,
key: &'a str,
expected: Option<String>,
value: String,
ttl_seconds: Option<u64>,
) -> SecondaryStorageFuture<'a, bool>;
/// Atomically delete the key only when the currently stored value matches
/// `expected`. `expected == None` means the key must already be absent and
/// therefore no deletion is performed.
///
/// Implementations must perform the comparison and deletion as a single
/// backend operation. A `get` followed by `delete` is not sufficient for
/// shared or multi-process storage because concurrent writers can race the
/// deletion.
fn delete_if_value<'a>(
&'a self,
key: &'a str,
expected: Option<String>,
) -> SecondaryStorageFuture<'a, bool>;
}