From e559259686f984fdcce5669f0ab8c6dc27d76077 Mon Sep 17 00:00:00 2001 From: Vika Date: Wed, 27 Oct 2021 06:27:13 +0300 Subject: Deprecated Redis backend and added a database migration tool (untested, beware) --- src/database/file/mod.rs | 2 +- src/database/mod.rs | 42 +++++++++++++++++++++++++++++------------- src/database/redis/mod.rs | 26 ++++++++++++++++++++------ 3 files changed, 50 insertions(+), 20 deletions(-) (limited to 'src/database') diff --git a/src/database/file/mod.rs b/src/database/file/mod.rs index f58317e..1e0102a 100644 --- a/src/database/file/mod.rs +++ b/src/database/file/mod.rs @@ -402,7 +402,7 @@ impl Storage for FileStorage { } } let posts = stream::iter(posts_iter) - .map(|url| async move { + .map(|url: String| async move { self.get_post(&url).await }) .buffered(std::cmp::min(3, limit)) diff --git a/src/database/mod.rs b/src/database/mod.rs index 7c67e42..4e74c8f 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -3,32 +3,46 @@ use crate::indieauth::User; use async_trait::async_trait; use serde::{Deserialize, Serialize}; -#[cfg(redis)] -mod redis; -#[cfg(redis)] -pub use crate::database::redis::RedisStorage; -#[cfg(all(redis, test))] -pub use redis::tests::{get_redis_instance, RedisInstance}; +//#[cfg(feature="redis")] +//mod redis; +//#[cfg(feature="redis")] +//pub use crate::database::redis::RedisStorage; +//#[cfg(all(redis, test))] +//pub use redis::tests::{get_redis_instance, RedisInstance}; mod file; pub use crate::database::file::FileStorage; +/// Data structure representing a Micropub channel in the ?q=channels output. #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct MicropubChannel { + /// The channel's UID. It is usually also a publically accessible permalink URL. pub uid: String, + /// The channel's user-friendly name used to recognize it in lists. pub name: String, } +/// Enum representing different errors that might occur during the database query. #[derive(Debug, Clone, Copy)] pub enum ErrorKind { + /// Backend error (e.g. database connection error) Backend, + /// Error due to insufficient contextual permissions for the query PermissionDenied, + /// Error due to the database being unable to parse JSON returned from the backing storage. + /// Usually indicative of someone fiddling with the database manually instead of using proper tools. JsonParsing, + /// - ErrorKind::NotFound - equivalent to a 404 error. Note, some requests return an Option, + /// in which case None is also equivalent to a 404. NotFound, + /// The user's query or request to the database was malformed. Used whenever the database processes + /// the user's query directly, such as when editing posts inside of the database (e.g. Redis backend) BadRequest, + /// - ErrorKind::Other - when something so weird happens that it becomes undescribable. Other, } +/// Error signalled from the database. #[derive(Debug)] pub struct StorageError { msg: String, @@ -115,6 +129,7 @@ impl StorageError { pub fn kind(&self) -> ErrorKind { self.kind } + /// Get the message as a string slice. pub fn msg(&self) -> &str { &self.msg } @@ -238,8 +253,8 @@ pub trait Storage: Clone + Send + Sync { #[cfg(test)] mod tests { - #[cfg(redis)] - use super::redis::tests::get_redis_instance; + //#[cfg(feature="redis")] + //use super::redis::tests::get_redis_instance; use super::{MicropubChannel, Storage}; use serde_json::json; use paste::paste; @@ -404,10 +419,11 @@ mod tests { "Vika's Hideout" ); } - macro_rules! redis_test { + + /*macro_rules! redis_test { ($func_name:expr) => { paste! { - #[cfg(redis)] + #[cfg(feature="redis")] #[async_std::test] async fn [] () { test_logger::ensure_env_logger_initialized(); @@ -419,7 +435,7 @@ mod tests { } } } - } + }*/ macro_rules! file_test { ($func_name:expr) => { @@ -435,10 +451,10 @@ mod tests { } } - redis_test!(test_backend_basic_operations); + /*redis_test!(test_backend_basic_operations); redis_test!(test_backend_get_channel_list); redis_test!(test_backend_settings); - redis_test!(test_backend_update); + redis_test!(test_backend_update);*/ file_test!(test_backend_basic_operations); file_test!(test_backend_get_channel_list); file_test!(test_backend_settings); diff --git a/src/database/redis/mod.rs b/src/database/redis/mod.rs index f1724b7..eeaa3f2 100644 --- a/src/database/redis/mod.rs +++ b/src/database/redis/mod.rs @@ -2,6 +2,7 @@ use async_trait::async_trait; use futures::stream; use futures_util::FutureExt; use futures_util::StreamExt; +use futures_util::TryStream; use futures_util::TryStreamExt; use lazy_static::lazy_static; use log::error; @@ -225,9 +226,13 @@ impl Storage for RedisStorage { } } } + async fn fetch_post_for_feed(url: String) -> Option { + return Some(serde_json::json!({})); + } let posts = stream::iter(posts_iter) - .map(|url| async move { - match self.redis.get().await { + .map(|url: String| async move { + return Ok(fetch_post_for_feed(url).await); + /*match self.redis.get().await { Ok(mut conn) => { match conn.hget::<&str, &str, Option>("posts", &url).await { Ok(post) => match post { @@ -241,18 +246,21 @@ impl Storage for RedisStorage { } } Err(err) => Err(StorageError::with_source(ErrorKind::Backend, "Error getting a connection from the pool", Box::new(err))) - } + }*/ }) // TODO: determine the optimal value for this buffer // It will probably depend on how often can you encounter a private post on the page // It shouldn't be too large, or we'll start fetching too many posts from the database // It MUST NOT be larger than the typical page size // It MUST NOT be a significant amount of the connection pool size - .buffered(std::cmp::min(3, limit)) + //.buffered(std::cmp::min(3, limit)) // Hack to unwrap the Option and sieve out broken links // Broken links return None, and Stream::filter_map skips all Nones. - .try_filter_map(|post: Option| async move { Ok(post) }) - .try_filter_map(|post| async move { Ok(filter_post(post, user)) }) + // I wonder if one can use try_flatten() here somehow akin to iters + .try_filter_map(|post| async move { Ok(post) }) + .try_filter_map(|post| async move { + Ok(filter_post(post, user)) + }) .take(limit); match posts.try_collect::>().await { Ok(posts) => feed["children"] = json!(posts), @@ -312,6 +320,12 @@ impl RedisStorage { Err(e) => Err(e.into()), } } + + pub async fn conn(&self) -> Result> { + self.redis.get().await.map_err(|e| StorageError::with_source( + ErrorKind::Backend, "Error getting a connection from the pool", Box::new(e) + )) + } } #[cfg(test)] -- cgit 1.4.1