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}