about summary refs log tree commit diff
path: root/src/database
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2024-08-26 20:25:20 +0300
committerVika <vika@fireburn.ru>2024-08-26 20:25:20 +0300
commit806f5fbfabd914d27ff3fb2e822e1c3869068859 (patch)
treecc805cfb7ef5af3d7e26075106d2663e5ca2dd67 /src/database
parent14e58b4137f8f77af43cad8b712596c2e1ab7e8a (diff)
Set MSRV to 1.75, remove #[async_trait] declarations whenever possible
Axum still uses `async_trait`, let them do whatever they want. I will
no longer be subject to the humiliation of trying to dig through
lifetime errors and unreadable declarations. Also I don't fucking care
about MSRV, I'm not a library. If you don't have modern Rust, get one.
Diffstat (limited to 'src/database')
-rw-r--r--src/database/file/mod.rs6
-rw-r--r--src/database/memory.rs6
-rw-r--r--src/database/mod.rs51
-rw-r--r--src/database/postgres/mod.rs8
-rw-r--r--src/database/redis/mod.rs2
5 files changed, 33 insertions, 40 deletions
diff --git a/src/database/file/mod.rs b/src/database/file/mod.rs
index 117ba17..10d6079 100644
--- a/src/database/file/mod.rs
+++ b/src/database/file/mod.rs
@@ -1,7 +1,6 @@
 //#![warn(clippy::unwrap_used)]
 use crate::database::{ErrorKind, Result, settings, Storage, StorageError};
 use crate::micropub::{MicropubUpdate, MicropubPropertyDeletion};
-use async_trait::async_trait;
 use futures::{stream, StreamExt, TryStreamExt};
 use kittybox_util::MentionType;
 use serde_json::json;
@@ -245,7 +244,6 @@ async fn hydrate_author<S: Storage>(
     }
 }
 
-#[async_trait]
 impl Storage for FileStorage {
     async fn new(url: &'_ url::Url) -> Result<Self> {
         // TODO: sanity check
@@ -630,7 +628,7 @@ impl Storage for FileStorage {
     }
 
     #[tracing::instrument(skip(self))]
-    async fn get_setting<S: settings::Setting<'a>, 'a>(&self, user: &url::Url) -> Result<S> {
+    async fn get_setting<S: settings::Setting>(&self, user: &url::Url) -> Result<S> {
         debug!("User for getting settings: {}", user);
         let mut path = relative_path::RelativePathBuf::new();
         path.push(user.authority());
@@ -651,7 +649,7 @@ impl Storage for FileStorage {
     }
 
     #[tracing::instrument(skip(self))]
-    async fn set_setting<S: settings::Setting<'a> + 'a, 'a>(&self, user: &'a url::Url, value: S::Data) -> Result<()> {
+    async fn set_setting<S: settings::Setting>(&self, user: &url::Url, value: S::Data) -> Result<()> {
         let mut path = relative_path::RelativePathBuf::new();
         path.push(user.authority());
         path.push("settings");
diff --git a/src/database/memory.rs b/src/database/memory.rs
index be37fed..a4ffc7b 100644
--- a/src/database/memory.rs
+++ b/src/database/memory.rs
@@ -1,5 +1,4 @@
 #![allow(clippy::todo)]
-use async_trait::async_trait;
 use futures_util::FutureExt;
 use serde_json::json;
 use std::collections::HashMap;
@@ -14,7 +13,6 @@ pub struct MemoryStorage {
     pub channels: Arc<RwLock<HashMap<url::Url, Vec<String>>>>,
 }
 
-#[async_trait]
 impl Storage for MemoryStorage {
     async fn new(_url: &url::Url) -> Result<Self> {
         Ok(Self::default())
@@ -220,12 +218,12 @@ impl Storage for MemoryStorage {
     }
 
     #[allow(unused_variables)]
-    async fn get_setting<S: settings::Setting<'a>, 'a>(&'_ self, user: &url::Url) -> Result<S> {
+    async fn get_setting<S: settings::Setting>(&'_ self, user: &url::Url) -> Result<S> {
         todo!()
     }
 
     #[allow(unused_variables)]
-    async fn set_setting<S: settings::Setting<'a> + 'a, 'a>(&self, user: &'a url::Url, value: S::Data) -> Result<()> {
+    async fn set_setting<S: settings::Setting>(&self, user: &url::Url, value: S::Data) -> Result<()> {
         todo!()
     }
 
diff --git a/src/database/mod.rs b/src/database/mod.rs
index 3b13cb3..058fc0c 100644
--- a/src/database/mod.rs
+++ b/src/database/mod.rs
@@ -1,7 +1,6 @@
 #![warn(missing_docs)]
-use std::borrow::Cow;
+use std::{borrow::Cow, future::Future};
 
-use async_trait::async_trait;
 use kittybox_util::MentionType;
 
 mod file;
@@ -54,7 +53,7 @@ pub mod settings {
     /// **Note**: this trait is sealed to prevent external
     /// implementations, as it wouldn't make sense to add new settings
     /// that aren't used by Kittybox itself.
-    pub trait Setting<'de>: private::Sealed + std::fmt::Debug + Default + Clone + serde::Serialize + serde::de::DeserializeOwned + /*From<Settings> +*/ Send + Sync {
+    pub trait Setting: private::Sealed + std::fmt::Debug + Default + Clone + serde::Serialize + serde::de::DeserializeOwned + /*From<Settings> +*/ Send + Sync + 'static {
         /// The data that the setting carries.
         type Data: std::fmt::Debug + Send + Sync;
         /// The string ID for the setting, usable as an identifier in the database.
@@ -80,7 +79,7 @@ pub mod settings {
         }
     }
     impl private::Sealed for SiteName {}
-    impl Setting<'_> for SiteName {
+    impl Setting for SiteName {
         type Data = String;
         const ID: &'static str = "site_name";
 
@@ -96,7 +95,7 @@ pub mod settings {
     #[derive(Debug, Default, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)]
     pub struct Webring(bool);
     impl private::Sealed for Webring {}
-    impl Setting<'_> for Webring {
+    impl Setting for Webring {
         type Data = bool;
         const ID: &'static str = "webring";
 
@@ -210,39 +209,38 @@ pub type Result<T> = std::result::Result<T, StorageError>;
 ///
 /// Implementations should note that all methods listed on this trait MUST be fully atomic
 /// or lock the database so that write conflicts or reading half-written data should not occur.
-#[async_trait]
 pub trait Storage: std::fmt::Debug + Clone + Send + Sync {
     /// Initialize Self from a URL, possibly performing initialization.
-    async fn new(url: &'_ url::Url) -> Result<Self>;
+    fn new(url: &url::Url) -> impl Future<Output = Result<Self>> + Send;
     /// Return the list of categories used in blog posts of a specified blog.
-    async fn categories(&self, url: &str) -> Result<Vec<String>>;
+    fn categories(&self, url: &str) -> impl Future<Output = Result<Vec<String>>> + Send;
 
     /// Check if a post exists in the database.
-    async fn post_exists(&self, url: &str) -> Result<bool>;
+    fn post_exists(&self, url: &str) -> impl Future<Output = Result<bool>> + Send;
 
     /// Load a post from the database in MF2-JSON format, deserialized from JSON.
-    async fn get_post(&self, url: &str) -> Result<Option<serde_json::Value>>;
+    fn get_post(&self, url: &str) -> impl Future<Output = Result<Option<serde_json::Value>>> + Send;
 
     /// Save a post to the database as an MF2-JSON structure.
     ///
     /// Note that the `post` object MUST have `post["properties"]["uid"][0]` defined.
-    async fn put_post(&self, post: &'_ serde_json::Value, user: &url::Url) -> Result<()>;
+    fn put_post(&self, post: &serde_json::Value, user: &url::Url) -> impl Future<Output = Result<()>> + Send;
 
     /// Add post to feed. Some database implementations might have optimized ways to do this.
     #[tracing::instrument(skip(self))]
-    async fn add_to_feed(&self, feed: &'_ str, post: &'_ str) -> Result<()> {
+    fn add_to_feed(&self, feed: &str, post: &str) -> impl Future<Output = Result<()>> + Send {
         tracing::debug!("Inserting {} into {} using `update_post`", post, feed);
         self.update_post(feed, serde_json::from_value(
             serde_json::json!({"add": {"children": [post]}})).unwrap()
-        ).await
+        )
     }
     /// Remove post from feed. Some database implementations might have optimized ways to do this.
     #[tracing::instrument(skip(self))]
-    async fn remove_from_feed(&self, feed: &str, post: &str) -> Result<()> {
+    fn remove_from_feed(&self, feed: &str, post: &str) -> impl Future<Output = Result<()>> + Send {
         tracing::debug!("Removing {} into {} using `update_post`", post, feed);
         self.update_post(feed, serde_json::from_value(
             serde_json::json!({"delete": {"children": [post]}})).unwrap()
-        ).await
+        )
     }
 
     /// Modify a post using an update object as defined in the
@@ -253,11 +251,11 @@ pub trait Storage: std::fmt::Debug + Clone + Send + Sync {
     /// each other's changes or simply corrupting something. Rejecting
     /// is allowed in case of concurrent updates if waiting for a lock
     /// cannot be done.
-    async fn update_post(&self, url: &str, update: MicropubUpdate) -> Result<()>;
+    fn update_post(&self, url: &str, update: MicropubUpdate) -> impl Future<Output = Result<()>> + Send;
 
     /// Get a list of channels available for the user represented by
     /// the `user` domain to write to.
-    async fn get_channels(&self, user: &url::Url) -> Result<Vec<MicropubChannel>>;
+    fn get_channels(&self, user: &url::Url) -> impl Future<Output = Result<Vec<MicropubChannel>>> + Send;
 
     /// Fetch a feed at `url` and return an h-feed object containing
     /// `limit` posts after a post by url `after`, filtering the content
@@ -275,13 +273,14 @@ pub trait Storage: std::fmt::Debug + Clone + Send + Sync {
     /// parallel from the database, preferably make this method use a
     /// connection pool to reduce overhead of creating a database
     /// connection per post for parallel fetching.
-    async fn read_feed_with_limit(
+    #[deprecated]
+    fn read_feed_with_limit(
         &self,
-        url: &'_ str,
+        url: &str,
         after: Option<&str>,
         limit: usize,
         user: Option<&url::Url>,
-    ) -> Result<Option<serde_json::Value>>;
+    ) -> impl Future<Output = Result<Option<serde_json::Value>>> + Send;
 
     /// Fetch a feed at `url` and return an h-feed object containing
     /// `limit` posts after a `cursor` (filtering the content in
@@ -301,22 +300,22 @@ pub trait Storage: std::fmt::Debug + Clone + Send + Sync {
     /// parallel from the database, preferably make this method use a
     /// connection pool to reduce overhead of creating a database
     /// connection per post for parallel fetching.
-    async fn read_feed_with_cursor(
+    fn read_feed_with_cursor(
         &self,
         url: &'_ str,
         cursor: Option<&'_ str>,
         limit: usize,
         user: Option<&url::Url>
-    ) -> Result<Option<(serde_json::Value, Option<String>)>>;
+    ) -> impl Future<Output = Result<Option<(serde_json::Value, Option<String>)>>> + Send;
 
     /// Deletes a post from the database irreversibly. Must be idempotent.
-    async fn delete_post(&self, url: &'_ str) -> Result<()>;
+    fn delete_post(&self, url: &'_ str) -> impl Future<Output = Result<()>> + Send;
 
     /// Gets a setting from the setting store and passes the result.
-    async fn get_setting<S: Setting<'a>, 'a>(&'_ self, user: &url::Url) -> Result<S>;
+    fn get_setting<S: Setting>(&self, user: &url::Url) -> impl Future<Output = Result<S>> + Send;
 
     /// Commits a setting to the setting store.
-    async fn set_setting<S: Setting<'a> + 'a, 'a>(&self, user: &'a url::Url, value: S::Data) -> Result<()>;
+    fn set_setting<S: Setting>(&self, user: &url::Url, value: S::Data) -> impl Future<Output = Result<()>> + Send;
 
     /// Add (or update) a webmention on a certian post.
     ///
@@ -332,7 +331,7 @@ pub trait Storage: std::fmt::Debug + Clone + Send + Sync {
     ///
     /// Besides, it may even allow for nice tricks like storing the
     /// webmentions separately and rehydrating them on feed reads.
-    async fn add_or_update_webmention(&self, target: &str, mention_type: MentionType, mention: serde_json::Value) -> Result<()>;
+    fn add_or_update_webmention(&self, target: &str, mention_type: MentionType, mention: serde_json::Value) -> impl Future<Output = Result<()>> + Send;
 }
 
 #[cfg(test)]
diff --git a/src/database/postgres/mod.rs b/src/database/postgres/mod.rs
index b2d4339..83e04c7 100644
--- a/src/database/postgres/mod.rs
+++ b/src/database/postgres/mod.rs
@@ -45,7 +45,6 @@ impl PostgresStorage {
     }
 }
 
-#[async_trait::async_trait]
 impl Storage for PostgresStorage {
     /// Construct a new [`PostgresStorage`] from an URI string and run
     /// migrations on the database.
@@ -189,8 +188,9 @@ WHERE
 
         txn.commit().await.map_err(Into::into)
     }
+
     #[tracing::instrument(skip(self))]
-    async fn update_post(&self, url: &'_ str, update: MicropubUpdate) -> Result<()> {
+    async fn update_post(&self, url: &str, update: MicropubUpdate) -> Result<()> {
         tracing::debug!("Updating post {}", url);
         let mut txn = self.db.begin().await?;
         let (uid, mut post) = sqlx::query_as::<_, (String, serde_json::Value)>("SELECT uid, mf2 FROM kittybox.mf2_json WHERE uid = $1 OR mf2['properties']['url'] ? $1 FOR UPDATE")
@@ -348,7 +348,7 @@ LIMIT $2"
     }
 
     #[tracing::instrument(skip(self))]
-    async fn get_setting<S: Setting<'a>, 'a>(&'_ self, user: &url::Url) -> Result<S> {
+    async fn get_setting<S: Setting>(&'_ self, user: &url::Url) -> Result<S> {
         match sqlx::query_as::<_, (serde_json::Value,)>("SELECT kittybox.get_setting($1, $2)")
             .bind(user.authority())
             .bind(S::ID)
@@ -361,7 +361,7 @@ LIMIT $2"
     }
 
     #[tracing::instrument(skip(self))]
-    async fn set_setting<S: Setting<'a> + 'a, 'a>(&self, user: &'a url::Url, value: S::Data) -> Result<()> {
+    async fn set_setting<S: Setting>(&self, user: &url::Url, value: S::Data) -> Result<()> {
         sqlx::query("SELECT kittybox.set_setting($1, $2, $3)")
             .bind(user.authority())
             .bind(S::ID)
diff --git a/src/database/redis/mod.rs b/src/database/redis/mod.rs
index 39ee852..e92a773 100644
--- a/src/database/redis/mod.rs
+++ b/src/database/redis/mod.rs
@@ -1,4 +1,3 @@
-use async_trait::async_trait;
 use futures::stream;
 use futures_util::FutureExt;
 use futures_util::StreamExt;
@@ -63,7 +62,6 @@ pub struct RedisStorage {
     redis: mobc::Pool<RedisConnectionManager>,
 }
 
-#[async_trait]
 impl Storage for RedisStorage {
     async fn get_setting<'a>(&self, setting: &'a str, user: &'a str) -> Result<String> {
         let mut conn = self.redis.get().await.map_err(|e| StorageError::with_source(ErrorKind::Backend, "Error getting a connection from the pool", Box::new(e)))?;