Skip to main content

libqaul_types/
services.rs

1//! Application service management and utilities
2//!
3//! An application using libqaul is called a "service". qaul.net (the
4//! application) is simply a collection of services that expose a
5//! common UI for users to interact with each other.  A service
6//! doesn't need to be user-facing, or have a UI.
7//!
8//! Via the [`qrpc`] message bus it is possible for arbitrary
9//! processes to interact with other services, and libqaul instances.
10//! Because libqaul implements encrypted at-rest storage, this
11//! mechanism is exposed to services via this API.  This way your
12//! application can't accidentally leak user metadata.
13//!
14//! [`qrpc`]: https://docs.qaul.net/api/qrpc-sdk/index.html
15
16use crate::users::UserAuth;
17use serde::{Deserialize, Serialize};
18use std::collections::BTreeMap;
19use std::ops::{Deref, DerefMut};
20
21/// An arbitrary map of metadata that can be stored by a service
22///
23/// Data is stored per service/per user and is tagged with search
24/// tags.  This structure (and API) can be used to store service
25/// related data on a device that will be encrypted and can be loaded
26/// on reboot, meaning that your service doesn't have to worry about
27/// storing things securely on different platforms.
28///
29/// `MetadataMap` has a builder API that makes constructing initial
30/// maps easier than just providing an already initialised BTreeMap.
31#[derive(Debug, Default, Clone, Eq, PartialEq)]
32pub struct MetadataMap {
33    name: String,
34    map: BTreeMap<String, Vec<u8>>,
35}
36
37impl MetadataMap {
38    /// Creates a new, empty metadata map
39    pub fn new<S: Into<String>>(name: S) -> Self {
40        Self {
41            name: name.into(),
42            map: Default::default(),
43        }
44    }
45
46    /// Create a metadata map from a name and initialised map construct
47    ///
48    /// ```
49    /// # use libqaul_types::services::MetadataMap;
50    /// MetadataMap::from("numbers", vec![("fav", vec![1, 2, 3, 4])]);
51    /// ```
52    ///
53    /// Because from takes `IntoIterator`, you can also initialise
54    /// your map in-place:
55    ///
56    /// ```
57    /// # use libqaul_types::services::MetadataMap;
58    /// MetadataMap::from("numbers", vec![
59    ///     ("fav", vec![1, 2, 3, 4]),
60    ///     ("prime", vec![1, 3, 5, 7, 11]),
61    ///     ("acab", vec![13, 12]),
62    /// ]);
63    /// ```
64    pub fn from<S, K, M, V>(name: S, map: M) -> Self
65    where
66        S: Into<String>,
67        K: Into<String>,
68        M: IntoIterator<Item = (K, V)>,
69        V: IntoIterator<Item = u8>,
70    {
71        let name = name.into();
72        let map = map
73            .into_iter()
74            .map(|(k, v)| (k.into(), v.into_iter().collect()))
75            .collect();
76        Self { name, map }
77    }
78
79    /// Return this entries name
80    pub fn name(&self) -> &String {
81        &self.name
82    }
83
84    /// Add (and override) a key-value map and return the modified map
85    pub fn add<K, V>(mut self, k: K, v: V) -> Self
86    where
87        K: Into<String>,
88        V: Into<Vec<u8>>,
89    {
90        self.map.insert(k.into(), v.into());
91        self
92    }
93
94    /// Delete a key and return the modified map
95    pub fn delete<K: Into<String>>(mut self, k: K) -> Self {
96        self.map.remove(&k.into());
97        self
98    }
99}
100
101impl Deref for MetadataMap {
102    type Target = BTreeMap<String, Vec<u8>>;
103    fn deref(&self) -> &Self::Target {
104        &self.map
105    }
106}
107
108impl DerefMut for MetadataMap {
109    fn deref_mut(&mut self) -> &mut Self::Target {
110        &mut self.map
111    }
112}
113
114/// Represents a service using libqaul
115///
116/// Via this type it's possible to either perform actions as a
117/// particular survice, or none, which means that all service's events
118/// become available.  While this is probably not desirable (and
119/// should be turned off) in most situations, this way a user-level
120/// service can do very powerful things with the "raw" netork traffic
121/// of a qaul network.
122#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
123pub enum Service {
124    /// Get access to all service's events
125    // One of the three most common passwords, you know?
126    God,
127    /// Service by domain qualified name (e.g. `net.qaul.chat`)
128    Name(String),
129}
130
131impl<T> From<T> for Service
132where
133    T: Into<String>,
134{
135    fn from(t: T) -> Self {
136        Self::Name(t.into())
137    }
138}
139
140/// Event type that can be sent to services to react to state changes
141pub enum ServiceEvent {
142    Open(UserAuth),
143    Close(UserAuth),
144}