interface/directory/
dir.rs

1use std::collections::HashMap;
2use std::net::IpAddr;
3use std::sync::Arc;
4
5use anyhow::Result;
6
7use async_trait::async_trait;
8
9pub use rapidquery::Expression;
10
11use serde::{Deserialize, Serialize};
12
13use crate::{BlobInfo, BlobInfoRequest, BlobMeta, ExpressionField, FieldValue, TaggedFieldValue};
14
15#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
16#[serde(deny_unknown_fields)]
17pub struct Hit {
18    pub id: String,
19    pub meta: BlobMeta,
20    pub url: String,
21}
22
23impl Hit {
24    pub fn new(id: String, meta: BlobMeta, url: String) -> Self {
25        Self { id, meta, url }
26    }
27}
28
29#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
30#[serde(deny_unknown_fields)]
31pub struct FacetResponse {
32    pub tags: HashMap<String, u64>,
33    pub meta: HashMap<String, HashMap<FieldValue, u64>>,
34}
35
36/// The results of a query.
37#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
38#[serde(deny_unknown_fields)]
39pub struct QueryResponse {
40    /// The number of hits returned with this response.
41    pub count: usize,
42
43    /// The total number of hits.
44    pub total: usize,
45
46    /// The query hits.
47    pub hits: Vec<Hit>,
48
49    /// The facets computed for this query.
50    ///
51    /// Returned only if requested with the query.
52    pub facets: Option<FacetResponse>,
53}
54
55#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
56pub enum RedirectInfo {
57    Automatic {
58        public_address: IpAddr,
59        local_address: IpAddr,
60        subnet_mask: IpAddr,
61    },
62    Static {
63        static_address: IpAddr,
64    },
65}
66
67#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
68#[serde(deny_unknown_fields)]
69pub struct StorageNodeInfo {
70    pub id: String,
71    pub redirect_info: RedirectInfo,
72    pub port: u16,
73    pub size: u64,
74    pub available_space: u64,
75}
76
77/// Data sent back to the storage node from the directory.
78#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
79#[serde(deny_unknown_fields)]
80pub struct StorageNodeResponseData {
81    pub rebuild_requested: bool,
82}
83
84#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
85#[serde(deny_unknown_fields)]
86pub struct MetadataList {
87    pub tags: HashMap<String, usize>,
88    pub fields: HashMap<String, HashMap<FieldValue, usize>>,
89}
90
91/// A sorting order.
92#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)]
93#[serde(rename_all = "snake_case")]
94pub enum SortOrder {
95    CreationAscending,
96    CreationDescending,
97}
98
99/// A query that can be sent to a Menmos cluster.
100#[derive(Clone, Debug, Deserialize, Hash, Serialize, PartialEq, Eq)]
101#[serde(deny_unknown_fields)]
102pub struct Query {
103    /// The query expression.
104    pub expression: Expression<ExpressionField>,
105    pub from: usize,
106    pub size: usize,
107    pub sign_urls: bool,
108    pub facets: bool,
109    // TODO: Permit requesting facets for specific tags instead of doing it for all.
110    pub sort_order: SortOrder,
111}
112
113impl Query {
114    pub fn with_expression<S: Into<String>>(mut self, expression: S) -> Result<Self> {
115        self.expression = Expression::parse(expression.into())?;
116        Ok(self)
117    }
118
119    #[must_use]
120    pub fn and_tag<S: Into<String>>(mut self, tag: S) -> Self {
121        let new_expr = Expression::Field(ExpressionField::Tag { tag: tag.into() });
122        self.expression = Expression::And {
123            and: (Box::from(self.expression), Box::from(new_expr)),
124        };
125        self
126    }
127
128    #[must_use]
129    pub fn and_field<K: Into<String>, V: Into<FieldValue>>(mut self, k: K, v: V) -> Self {
130        let new_expr = Expression::Field(ExpressionField::Field {
131            key: k.into(),
132            value: v.into(),
133        });
134        self.expression = Expression::And {
135            and: (Box::from(self.expression), Box::from(new_expr)),
136        };
137        self
138    }
139
140    #[must_use]
141    pub fn with_from(mut self, f: usize) -> Self {
142        self.from = f;
143        self
144    }
145
146    #[must_use]
147    pub fn with_size(mut self, s: usize) -> Self {
148        self.size = s;
149        self
150    }
151
152    #[must_use]
153    pub fn with_facets(mut self, f: bool) -> Self {
154        self.facets = f;
155        self
156    }
157
158    pub fn with_sort_order(mut self, sort_order: SortOrder) -> Self {
159        self.sort_order = sort_order;
160        self
161    }
162}
163
164impl Default for Query {
165    fn default() -> Self {
166        Query {
167            expression: Default::default(),
168            from: 0,
169            size: 30,
170            sign_urls: true,
171            facets: false,
172            sort_order: SortOrder::CreationAscending,
173        }
174    }
175}
176
177#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
178#[serde(deny_unknown_fields)]
179pub struct RoutingConfig {
180    /// The field name to use for routing.
181    pub routing_key: String,
182
183    /// A map of field values -> storage node IDs.
184    pub routes: HashMap<FieldValue, String>,
185}
186
187impl RoutingConfig {
188    pub fn new<S: Into<String>>(key: S) -> Self {
189        Self {
190            routing_key: key.into(),
191            routes: HashMap::new(),
192        }
193    }
194
195    #[must_use]
196    pub fn with_route<K: Into<FieldValue>, V: Into<String>>(
197        mut self,
198        field_value: K,
199        storage_node_id: V,
200    ) -> Self {
201        self.routes
202            .insert(field_value.into(), storage_node_id.into());
203        self
204    }
205}
206
207#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
208#[serde(deny_unknown_fields)]
209pub struct TaggedRoutingConfig {
210    /// The field name to use for routing.
211    pub routing_key: String,
212
213    /// A map of field values -> storage node IDs.
214    pub routes: HashMap<TaggedFieldValue, String>,
215}
216
217impl From<RoutingConfig> for TaggedRoutingConfig {
218    fn from(v: RoutingConfig) -> Self {
219        Self {
220            routing_key: v.routing_key,
221            routes: v
222                .routes
223                .into_iter()
224                .map(|(k, v)| (k.into(), v))
225                .collect::<HashMap<_, _>>(),
226        }
227    }
228}
229
230impl From<TaggedRoutingConfig> for RoutingConfig {
231    fn from(v: TaggedRoutingConfig) -> Self {
232        Self {
233            routing_key: v.routing_key,
234            routes: v
235                .routes
236                .into_iter()
237                .map(|(k, v)| (k.into(), v))
238                .collect::<HashMap<_, _>>(),
239        }
240    }
241}
242
243#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
244pub enum DirtyState {
245    Dirty,
246    Clean,
247}
248
249#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
250#[serde(deny_unknown_fields)]
251pub struct RoutingConfigState {
252    pub routing_config: RoutingConfig,
253    pub state: DirtyState,
254}
255
256#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
257#[serde(deny_unknown_fields)]
258pub struct TaggedRoutingConfigState {
259    pub routing_config: TaggedRoutingConfig,
260    pub state: DirtyState,
261}
262
263impl From<RoutingConfigState> for TaggedRoutingConfigState {
264    fn from(v: RoutingConfigState) -> Self {
265        Self {
266            routing_config: v.routing_config.into(),
267            state: v.state,
268        }
269    }
270}
271
272impl From<TaggedRoutingConfigState> for RoutingConfigState {
273    fn from(v: TaggedRoutingConfigState) -> Self {
274        Self {
275            routing_config: v.routing_config.into(),
276            state: v.state,
277        }
278    }
279}
280
281#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
282#[serde(deny_unknown_fields)]
283pub struct MoveInformation {
284    pub blob_id: String,
285    pub owner_username: String,
286    pub destination_node: StorageNodeInfo,
287}
288
289#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
290#[serde(rename_all = "snake_case")]
291pub enum RoutingAlgorithm {
292    RoundRobin,
293    MinSize,
294}
295
296#[async_trait]
297pub trait BlobIndexer {
298    async fn pick_node_for_blob(
299        &self,
300        blob_id: &str,
301        info_request: BlobInfoRequest,
302    ) -> Result<StorageNodeInfo>;
303    async fn get_blob_meta(&self, blob_id: &str, user: &str) -> Result<Option<BlobInfo>>;
304    async fn index_blob(&self, blob_id: &str, meta: BlobInfo, storage_node_id: &str) -> Result<()>;
305    async fn delete_blob(&self, blob_id: &str, username: &str) -> Result<Option<StorageNodeInfo>>;
306    async fn get_blob_storage_node(&self, blob_id: &str) -> Result<Option<StorageNodeInfo>>;
307    async fn clear(&self) -> Result<()>;
308    async fn flush(&self) -> Result<()>;
309}
310
311#[async_trait]
312pub trait RoutingConfigManager {
313    async fn get_routing_config(&self, user: &str) -> Result<Option<RoutingConfig>>;
314    async fn set_routing_config(&self, user: &str, config: &RoutingConfig) -> Result<()>;
315    async fn delete_routing_config(&self, user: &str) -> Result<()>;
316
317    async fn get_move_requests(&self, src_node: &str) -> Result<Vec<MoveInformation>>;
318
319    async fn flush(&self) -> Result<()>;
320}
321
322#[async_trait]
323pub trait NodeAdminController {
324    async fn register_storage_node(&self, def: StorageNodeInfo) -> Result<StorageNodeResponseData>;
325    async fn list_storage_nodes(&self) -> Result<Vec<StorageNodeInfo>>;
326
327    async fn start_rebuild(&self) -> Result<()>;
328    async fn rebuild_complete(&self, storage_node_id: &str) -> Result<()>;
329    async fn flush(&self) -> Result<()>;
330}
331
332#[async_trait]
333pub trait UserManagement {
334    async fn login(&self, user: &str, password: &str) -> Result<bool>;
335    async fn register(&self, user: &str, password: &str) -> Result<()>;
336    async fn has_user(&self, user: &str) -> Result<bool>;
337    async fn list(&self) -> Result<Vec<String>>;
338    async fn flush(&self) -> Result<()>;
339}
340
341#[async_trait]
342pub trait QueryExecutor {
343    async fn query(&self, q: &Query, username: &str) -> Result<QueryResponse>;
344    async fn query_move_requests(
345        &self,
346        query: &Query,
347        username: &str,
348        src_node: &str,
349    ) -> Result<Vec<String>>;
350    async fn list_metadata(
351        &self,
352        tags: Option<Vec<String>>,
353        meta_keys: Option<Vec<String>>,
354        username: &str,
355    ) -> Result<MetadataList>;
356}
357
358#[async_trait]
359pub trait DirectoryNode {
360    fn indexer(&self) -> Arc<dyn BlobIndexer + Send + Sync>;
361    fn routing(&self) -> Arc<dyn RoutingConfigManager + Send + Sync>;
362    fn admin(&self) -> Arc<dyn NodeAdminController + Send + Sync>;
363    fn user(&self) -> Arc<dyn UserManagement + Send + Sync>;
364    fn query(&self) -> Arc<dyn QueryExecutor + Send + Sync>;
365
366    async fn flush(&self) -> Result<()>;
367}
368
369pub type DynDirectoryNode = Arc<dyn DirectoryNode + Send + Sync>;