1use std::num::NonZeroUsize;
3
4use anyhow::Result;
5use bytes::Bytes;
6use serde::{Deserialize, Serialize};
7
8use crate::{AuthorId, Entry, NamespaceId};
9
10pub mod fs;
11mod pubkeys;
12mod util;
13pub use pubkeys::*;
14
15pub use fs::Store;
16
17pub(crate) const PEERS_PER_DOC_CACHE_SIZE: NonZeroUsize = match NonZeroUsize::new(5) {
19 Some(val) => val,
20 None => panic!("this is clearly non zero"),
21};
22
23#[derive(Debug, thiserror::Error)]
25pub enum OpenError {
26 #[error("Replica not found")]
28 NotFound,
29 #[error("{0}")]
31 Other(#[from] anyhow::Error),
32}
33
34pub trait DownloadPolicyStore {
36 fn get_download_policy(&mut self, namespace: &NamespaceId) -> Result<DownloadPolicy>;
38}
39
40impl<T: DownloadPolicyStore> DownloadPolicyStore for &mut T {
41 fn get_download_policy(&mut self, namespace: &NamespaceId) -> Result<DownloadPolicy> {
42 DownloadPolicyStore::get_download_policy(*self, namespace)
43 }
44}
45
46impl DownloadPolicyStore for crate::store::Store {
47 fn get_download_policy(&mut self, namespace: &NamespaceId) -> Result<DownloadPolicy> {
48 self.get_download_policy(namespace)
49 }
50}
51
52#[derive(Debug, Clone, Copy)]
54pub enum ImportNamespaceOutcome {
55 Inserted,
57 Upgraded,
59 NoChange,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
65pub enum DownloadPolicy {
66 NothingExcept(Vec<FilterKind>),
68 EverythingExcept(Vec<FilterKind>),
70}
71
72impl Default for DownloadPolicy {
73 fn default() -> Self {
74 DownloadPolicy::EverythingExcept(Vec::default())
75 }
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
80pub enum FilterKind {
81 Prefix(Bytes),
83 Exact(Bytes),
85}
86
87impl std::fmt::Display for FilterKind {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 let (kind, bytes) = match self {
91 FilterKind::Prefix(bytes) => ("prefix", bytes),
92 FilterKind::Exact(bytes) => ("exact", bytes),
93 };
94 let (encoding, repr) = match String::from_utf8(bytes.to_vec()) {
95 Ok(repr) => ("utf8", repr),
96 Err(_) => ("hex", hex::encode(bytes)),
97 };
98 write!(f, "{kind}:{encoding}:{repr}")
99 }
100}
101
102impl std::str::FromStr for FilterKind {
103 type Err = anyhow::Error;
104
105 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
106 let Some((kind, rest)) = s.split_once(':') else {
107 anyhow::bail!("missing filter kind, either \"prefix:\" or \"exact:\"")
108 };
109 let Some((encoding, rest)) = rest.split_once(':') else {
110 anyhow::bail!("missing encoding: either \"hex:\" or \"utf8:\"")
111 };
112
113 let is_exact = match kind {
114 "exact" => true,
115 "prefix" => false,
116 other => {
117 anyhow::bail!("expected filter kind \"prefix:\" or \"exact:\", found {other}")
118 }
119 };
120
121 let decoded = match encoding {
122 "utf8" => Bytes::from(rest.to_owned()),
123 "hex" => match hex::decode(rest) {
124 Ok(bytes) => Bytes::from(bytes),
125 Err(_) => anyhow::bail!("failed to decode hex"),
126 },
127 other => {
128 anyhow::bail!("expected encoding: either \"hex:\" or \"utf8:\", found {other}")
129 }
130 };
131
132 if is_exact {
133 Ok(FilterKind::Exact(decoded))
134 } else {
135 Ok(FilterKind::Prefix(decoded))
136 }
137 }
138}
139
140impl FilterKind {
141 pub fn matches(&self, key: impl AsRef<[u8]>) -> bool {
143 match self {
144 FilterKind::Prefix(prefix) => key.as_ref().starts_with(prefix),
145 FilterKind::Exact(expected) => expected == key.as_ref(),
146 }
147 }
148}
149
150impl DownloadPolicy {
151 pub fn matches(&self, entry: &Entry) -> bool {
153 let key = entry.key();
154 match self {
155 DownloadPolicy::NothingExcept(patterns) => {
156 patterns.iter().any(|pattern| pattern.matches(key))
157 }
158 DownloadPolicy::EverythingExcept(patterns) => {
159 patterns.iter().all(|pattern| !pattern.matches(key))
160 }
161 }
162 }
163}
164
165#[derive(Debug, Default)]
167pub struct QueryBuilder<K> {
168 kind: K,
169 filter_author: AuthorFilter,
170 filter_key: KeyFilter,
171 limit: Option<u64>,
172 offset: u64,
173 include_empty: bool,
174 sort_direction: SortDirection,
175}
176
177impl<K> QueryBuilder<K> {
178 pub fn include_empty(mut self) -> Self {
180 self.include_empty = true;
181 self
182 }
183 pub fn key_exact(mut self, key: impl AsRef<[u8]>) -> Self {
185 self.filter_key = KeyFilter::Exact(key.as_ref().to_vec().into());
186 self
187 }
188 pub fn key_prefix(mut self, key: impl AsRef<[u8]>) -> Self {
190 self.filter_key = KeyFilter::Prefix(key.as_ref().to_vec().into());
191 self
192 }
193 pub fn author(mut self, author: AuthorId) -> Self {
195 self.filter_author = AuthorFilter::Exact(author);
196 self
197 }
198 pub fn limit(mut self, limit: u64) -> Self {
200 self.limit = Some(limit);
201 self
202 }
203 pub fn offset(mut self, offset: u64) -> Self {
205 self.offset = offset;
206 self
207 }
208}
209
210#[derive(Debug, Clone, Default, Serialize, Deserialize)]
212pub struct FlatQuery {
213 sort_by: SortBy,
214}
215
216#[derive(Debug, Clone, Default, Serialize, Deserialize)]
218pub struct SingleLatestPerKeyQuery {}
219
220impl QueryBuilder<FlatQuery> {
221 pub fn sort_by(mut self, sort_by: SortBy, direction: SortDirection) -> Self {
225 self.kind.sort_by = sort_by;
226 self.sort_direction = direction;
227 self
228 }
229
230 pub fn build(self) -> Query {
232 Query::from(self)
233 }
234}
235
236impl QueryBuilder<SingleLatestPerKeyQuery> {
237 pub fn sort_direction(mut self, direction: SortDirection) -> Self {
242 self.sort_direction = direction;
243 self
244 }
245
246 pub fn build(self) -> Query {
248 Query::from(self)
249 }
250}
251
252impl From<QueryBuilder<SingleLatestPerKeyQuery>> for Query {
253 fn from(builder: QueryBuilder<SingleLatestPerKeyQuery>) -> Query {
254 Query {
255 kind: QueryKind::SingleLatestPerKey(builder.kind),
256 filter_author: builder.filter_author,
257 filter_key: builder.filter_key,
258 limit: builder.limit,
259 offset: builder.offset,
260 include_empty: builder.include_empty,
261 sort_direction: builder.sort_direction,
262 }
263 }
264}
265
266impl From<QueryBuilder<FlatQuery>> for Query {
267 fn from(builder: QueryBuilder<FlatQuery>) -> Query {
268 Query {
269 kind: QueryKind::Flat(builder.kind),
270 filter_author: builder.filter_author,
271 filter_key: builder.filter_key,
272 limit: builder.limit,
273 offset: builder.offset,
274 include_empty: builder.include_empty,
275 sort_direction: builder.sort_direction,
276 }
277 }
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct Query {
284 kind: QueryKind,
285 filter_author: AuthorFilter,
286 filter_key: KeyFilter,
287 limit: Option<u64>,
288 offset: u64,
289 include_empty: bool,
290 sort_direction: SortDirection,
291}
292
293impl Query {
294 pub fn all() -> QueryBuilder<FlatQuery> {
296 Default::default()
297 }
298 pub fn single_latest_per_key() -> QueryBuilder<SingleLatestPerKeyQuery> {
301 Default::default()
302 }
303
304 pub fn author(author: AuthorId) -> QueryBuilder<FlatQuery> {
306 Self::all().author(author)
307 }
308
309 pub fn key_exact(key: impl AsRef<[u8]>) -> QueryBuilder<FlatQuery> {
311 Self::all().key_exact(key)
312 }
313
314 pub fn key_prefix(prefix: impl AsRef<[u8]>) -> QueryBuilder<FlatQuery> {
316 Self::all().key_prefix(prefix)
317 }
318
319 pub fn limit(&self) -> Option<u64> {
321 self.limit
322 }
323
324 pub fn offset(&self) -> u64 {
326 self.offset
327 }
328}
329
330#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
332pub enum SortDirection {
333 #[default]
335 Asc,
336 Desc,
338}
339
340#[derive(derive_more::Debug, Clone, Serialize, Deserialize)]
341enum QueryKind {
342 #[debug("Flat {{ sort_by: {:?}}}", _0)]
343 Flat(FlatQuery),
344 #[debug("SingleLatestPerKey")]
345 SingleLatestPerKey(SingleLatestPerKeyQuery),
346}
347
348#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
350pub enum SortBy {
351 KeyAuthor,
353 #[default]
355 AuthorKey,
356}
357
358#[derive(Debug, Serialize, Deserialize, Clone, Default, Eq, PartialEq)]
360pub enum KeyFilter {
361 #[default]
363 Any,
364 Exact(Bytes),
366 Prefix(Bytes),
368}
369
370impl<T: AsRef<[u8]>> From<T> for KeyFilter {
371 fn from(value: T) -> Self {
372 KeyFilter::Exact(Bytes::copy_from_slice(value.as_ref()))
373 }
374}
375
376impl KeyFilter {
377 pub fn matches(&self, key: &[u8]) -> bool {
379 match self {
380 Self::Any => true,
381 Self::Exact(k) => &k[..] == key,
382 Self::Prefix(p) => key.starts_with(p),
383 }
384 }
385}
386
387#[derive(Debug, Serialize, Deserialize, Clone, Default, Eq, PartialEq)]
389pub enum AuthorFilter {
390 #[default]
392 Any,
393 Exact(AuthorId),
395}
396
397impl AuthorFilter {
398 pub fn matches(&self, author: &AuthorId) -> bool {
400 match self {
401 Self::Any => true,
402 Self::Exact(a) => a == author,
403 }
404 }
405}
406
407impl From<AuthorId> for AuthorFilter {
408 fn from(value: AuthorId) -> Self {
409 AuthorFilter::Exact(value)
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416
417 #[test]
418 fn test_filter_kind_encode_decode() {
419 const REPR: &str = "prefix:utf8:memes/futurama";
420 let filter: FilterKind = REPR.parse().expect("should decode");
421 assert_eq!(
422 filter,
423 FilterKind::Prefix(Bytes::from(String::from("memes/futurama")))
424 );
425 assert_eq!(filter.to_string(), REPR)
426 }
427}