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