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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! User management API scope

use crate::{core::Library, error::Result, utils::Id};
use serde::{Deserialize, Serialize};

/// Represents a database session
///
/// A session is either bound to the global scope (meaning the
/// lifetime of the database in memory), or a specific id, which you
/// can yield via `id()`.  To learn more about sessions, have a look
/// at the [`SessionsApi`][api]!
///
/// [api]: struct.SessionsApi.html
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Session {
    /// The global session, accessed on `load()`
    Global,
    /// A user-specific session with separate key tree
    Id(Id),
}

impl Session {
    /// Get the inner Id, if applicable
    pub(crate) fn id(&self) -> Option<Id> {
        match self {
            Self::Id(id) => Some(*id),
            Self::Global => None,
        }
    }
}

impl From<Id> for Session {
    fn from(id: Id) -> Self {
        Self::Id(id)
    }
}

/// Convenience type to represent the global namespace
pub const GLOBAL: Session = Session::Global;

/// Api scope wrapper for database sessions
///
/// A session is some random Id which is used as a namespace
/// identifier.  Each session namespace is encrypted independently,
/// with a unique key, and record tree.  This means that two paths
/// (say `/foo:bar`) can point to two separate records in the
/// database, if they belong to different sessions.
///
/// An important distiction to make here: a session is not ephemeral
/// but a long living namespace Id, similar to a user in a traditional
/// database.
pub struct SessionsApi<'alex> {
    pub(crate) inner: &'alex Library,
}

impl<'alex> SessionsApi<'alex> {
    /// List available sessions in this database
    pub async fn list(&self) -> Vec<Id> {
        vec![]
    }

    /// Open a previously created session
    pub async fn open(&self, id: Id, pw: &str) -> Result<Session> {
        let ref mut u = self.inner.users.write().await;
        u.open(id, pw).map(|_| Session::Id(id))
    }

    /// Close an active session
    pub async fn close(&self, id: Session) -> Result<()> {
        if let Some(id) = id.id() {
            let ref mut u = self.inner.users.write().await;
            u.close(id)
        } else {
            Ok(())
        }
    }

    /// Create a new session with a unique encryption key
    pub async fn create(&self, id: Id, pw: &str) -> Result<Session> {
        let ref mut u = self.inner.users.write().await;
        u.insert(id, pw).map(|_| Session::Id(id))
    }

    /// Remove a session Id and corresponding data from the database
    pub async fn destroy(&self, id: Session) -> Result<()> {
        if let Some(id) = id.id() {
            let ref mut u = self.inner.users.write().await;
            u.delete(id)
        } else {
            Ok(())
        }
    }
}