1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
use async_trait::async_trait;
use std::collections::HashMap;
use std::sync::Arc;
use async_std::sync::RwLock;
use futures_util::FutureExt;
use serde_json::json;
use crate::database::{Storage, Result, StorageError, ErrorKind, MicropubChannel};
use crate::indieauth::User;
#[derive(Clone)]
pub struct MemoryStorage {
pub mapping: Arc<RwLock<HashMap<String, serde_json::Value>>>,
pub channels: Arc<RwLock<HashMap<String, Vec<String>>>>
}
#[async_trait]
impl Storage for MemoryStorage {
async fn read_feed_with_limit<'a>(&self, url: &'a str, after: &'a Option<String>, limit: usize, user: &'a Option<String>) -> Result<Option<serde_json::Value>> {
todo!()
}
async fn update_post<'a>(&self, url: &'a str, update: serde_json::Value) -> Result<()> {
todo!()
}
async fn delete_post<'a>(&self, url: &'a str) -> Result<()> {
self.mapping.write().await.remove(url);
Ok(())
}
async fn post_exists(&self, url: &str) -> Result<bool> {
return Ok(self.mapping.read().await.contains_key(url))
}
async fn get_post(&self, url: &str) ->Result<Option<serde_json::Value>> {
let mapping = self.mapping.read().await;
match mapping.get(url) {
Some(val) => {
if let Some(new_url) = val["see_other"].as_str() {
match mapping.get(new_url) {
Some(val) => Ok(Some(val.clone())),
None => {
drop(mapping);
self.mapping.write().await.remove(url);
Ok(None)
}
}
} else {
Ok(Some(val.clone()))
}
},
_ => Ok(None)
}
}
async fn get_channels(&self, user: &User) -> Result<Vec<MicropubChannel>> {
match self.channels.read().await.get(&user.me.to_string()) {
Some(channels) => Ok(futures_util::future::join_all(channels.iter()
.map(|channel| self.get_post(channel)
.map(|result| result.unwrap())
.map(|post: Option<serde_json::Value>| {
if let Some(post) = post {
Some(MicropubChannel {
uid: post["properties"]["uid"][0].as_str().unwrap().to_string(),
name: post["properties"]["name"][0].as_str().unwrap().to_string()
})
} else { None }
})
).collect::<Vec<_>>()).await.into_iter().filter_map(|chan| chan).collect::<Vec<_>>()),
None => Ok(vec![])
}
}
async fn put_post<'a>(&self, post: &'a serde_json::Value) -> Result<()> {
let mapping = &mut self.mapping.write().await;
let key: &str;
match post["properties"]["uid"][0].as_str() {
Some(uid) => key = uid,
None => return Err(StorageError::new(ErrorKind::Other, "post doesn't have a UID"))
}
mapping.insert(key.to_string(), post.clone());
if post["properties"]["url"].is_array() {
for url in post["properties"]["url"].as_array().unwrap().iter().map(|i| i.as_str().unwrap().to_string()) {
if &url != key {
mapping.insert(url, json!({"see_other": key}));
}
}
}
if post["type"].as_array().unwrap().iter().any(|i| i == "h-feed") {
// This is a feed. Add it to the channels array if it's not already there.
println!("{:#}", post);
self.channels.write().await.entry(post["properties"]["author"][0].as_str().unwrap().to_string()).or_insert(vec![]).push(key.to_string())
}
Ok(())
}
}
impl MemoryStorage {
pub fn new() -> Self {
Self {
mapping: Arc::new(RwLock::new(HashMap::new())),
channels: Arc::new(RwLock::new(HashMap::new()))
}
}
}
|