From bfcc6e27e9bf997dd48f4162f99a20c5ddb082db Mon Sep 17 00:00:00 2001 From: William Casarin Date: Mon, 9 Dec 2024 09:35:34 -0800 Subject: [PATCH] rustfmt Signed-off-by: William Casarin --- .rustfmt.toml | 1 + shell.nix | 11 +- src/api_request_handler.rs | 236 ++++++++++------ src/nip98_auth.rs | 2 +- src/notepush_env.rs | 6 +- src/notification_manager/mod.rs | 4 +- src/notification_manager/nostr_event_cache.rs | 136 ++++++--- .../nostr_event_extensions.rs | 126 ++++++--- .../nostr_network_helper.rs | 54 +++- .../notification_manager.rs | 258 ++++++++++++------ src/notification_manager/utils.rs | 12 +- src/relay_connection.rs | 9 +- 12 files changed, 567 insertions(+), 288 deletions(-) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..32a9786 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +edition = "2018" diff --git a/shell.nix b/shell.nix index 627559f..e23df45 100644 --- a/shell.nix +++ b/shell.nix @@ -1,10 +1,11 @@ { pkgs ? import {} }: pkgs.mkShell { - buildInputs = [ - pkgs.cargo - pkgs.openssl - pkgs.pkg-config - pkgs.websocat + buildInputs = with pkgs; [ + cargo + rustfmt + openssl + pkg-config + websocat ]; } diff --git a/src/api_request_handler.rs b/src/api_request_handler.rs index 95c567a..60c1ef9 100644 --- a/src/api_request_handler.rs +++ b/src/api_request_handler.rs @@ -32,7 +32,7 @@ impl APIHandler { base_url, } } - + // MARK: - HTTP handling pub async fn handle_http_request( @@ -159,36 +159,53 @@ impl APIHandler { authorized_pubkey, }) } - + // MARK: - Router async fn handle_parsed_http_request( &self, parsed_request: &ParsedRequest, ) -> Result> { - - if let Some(url_params) = route_match(&Method::PUT, "/user-info/:pubkey/:deviceToken", &parsed_request) { + if let Some(url_params) = route_match( + &Method::PUT, + "/user-info/:pubkey/:deviceToken", + &parsed_request, + ) { return self.handle_user_info(parsed_request, &url_params).await; } - - if let Some(url_params) = route_match(&Method::DELETE, "/user-info/:pubkey/:deviceToken", &parsed_request) { - return self.handle_user_info_remove(parsed_request, &url_params).await; + + if let Some(url_params) = route_match( + &Method::DELETE, + "/user-info/:pubkey/:deviceToken", + &parsed_request, + ) { + return self + .handle_user_info_remove(parsed_request, &url_params) + .await; } - - if let Some(url_params) = route_match(&Method::GET, "/user-info/:pubkey/:deviceToken/preferences", &parsed_request) { + + if let Some(url_params) = route_match( + &Method::GET, + "/user-info/:pubkey/:deviceToken/preferences", + &parsed_request, + ) { return self.get_user_settings(parsed_request, &url_params).await; } - - if let Some(url_params) = route_match(&Method::PUT, "/user-info/:pubkey/:deviceToken/preferences", &parsed_request) { + + if let Some(url_params) = route_match( + &Method::PUT, + "/user-info/:pubkey/:deviceToken/preferences", + &parsed_request, + ) { return self.set_user_settings(parsed_request, &url_params).await; } - + Ok(APIResponse { status: StatusCode::NOT_FOUND, body: json!({ "error": "Not found" }), }) } - + // MARK: - Authentication async fn authenticate( @@ -209,7 +226,7 @@ impl APIHandler { ) .await) } - + // MARK: - Endpoint handlers async fn handle_user_info( @@ -220,30 +237,36 @@ impl APIHandler { // Early return if `deviceToken` is missing let device_token = match url_params.get("deviceToken") { Some(token) => token, - None => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "deviceToken is required on the URL" }), - }), + None => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "deviceToken is required on the URL" }), + }) + } }; - + // Early return if `pubkey` is missing let pubkey = match url_params.get("pubkey") { Some(key) => key, - None => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "pubkey is required on the URL" }), - }), + None => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "pubkey is required on the URL" }), + }) + } }; - + // Validate the `pubkey` and prepare it for use let pubkey = match nostr::PublicKey::from_hex(pubkey) { Ok(key) => key, - Err(_) => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "Invalid pubkey" }), - }), + Err(_) => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "Invalid pubkey" }), + }) + } }; - + // Early return if `pubkey` does not match `req.authorized_pubkey` if pubkey != req.authorized_pubkey { return Ok(APIResponse { @@ -251,9 +274,11 @@ impl APIHandler { body: json!({ "error": "Forbidden" }), }); } - + // Proceed with the main logic after passing all checks - self.notification_manager.save_user_device_info_if_not_present(pubkey, device_token).await?; + self.notification_manager + .save_user_device_info_if_not_present(pubkey, device_token) + .await?; Ok(APIResponse { status: StatusCode::OK, body: json!({ "message": "User info saved successfully" }), @@ -268,30 +293,36 @@ impl APIHandler { // Early return if `deviceToken` is missing let device_token = match url_params.get("deviceToken") { Some(token) => token, - None => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "deviceToken is required on the URL" }), - }), + None => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "deviceToken is required on the URL" }), + }) + } }; - + // Early return if `pubkey` is missing let pubkey = match url_params.get("pubkey") { Some(key) => key, - None => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "pubkey is required on the URL" }), - }), + None => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "pubkey is required on the URL" }), + }) + } }; - + // Validate the `pubkey` and prepare it for use let pubkey = match nostr::PublicKey::from_hex(pubkey) { Ok(key) => key, - Err(_) => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "Invalid pubkey" }), - }), + Err(_) => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "Invalid pubkey" }), + }) + } }; - + // Early return if `pubkey` does not match `req.authorized_pubkey` if pubkey != req.authorized_pubkey { return Ok(APIResponse { @@ -299,16 +330,18 @@ impl APIHandler { body: json!({ "error": "Forbidden" }), }); } - + // Proceed with the main logic after passing all checks - self.notification_manager.remove_user_device_info(pubkey, device_token).await?; - + self.notification_manager + .remove_user_device_info(pubkey, device_token) + .await?; + Ok(APIResponse { status: StatusCode::OK, body: json!({ "message": "User info removed successfully" }), }) } - + async fn set_user_settings( &self, req: &ParsedRequest, @@ -317,30 +350,36 @@ impl APIHandler { // Early return if `deviceToken` is missing let device_token = match url_params.get("deviceToken") { Some(token) => token, - None => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "deviceToken is required on the URL" }), - }), + None => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "deviceToken is required on the URL" }), + }) + } }; - + // Early return if `pubkey` is missing let pubkey = match url_params.get("pubkey") { Some(key) => key, - None => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "pubkey is required on the URL" }), - }), + None => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "pubkey is required on the URL" }), + }) + } }; - + // Validate the `pubkey` and prepare it for use let pubkey = match nostr::PublicKey::from_hex(pubkey) { Ok(key) => key, - Err(_) => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "Invalid pubkey" }), - }), + Err(_) => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "Invalid pubkey" }), + }) + } }; - + // Early return if `pubkey` does not match `req.authorized_pubkey` if pubkey != req.authorized_pubkey { return Ok(APIResponse { @@ -348,7 +387,7 @@ impl APIHandler { body: json!({ "error": "Forbidden" }), }); } - + // Proceed with the main logic after passing all checks let body = req.body_json()?; @@ -361,14 +400,20 @@ impl APIHandler { }); } }; - - self.notification_manager.save_user_notification_settings(&req.authorized_pubkey, device_token.to_string(), settings).await?; + + self.notification_manager + .save_user_notification_settings( + &req.authorized_pubkey, + device_token.to_string(), + settings, + ) + .await?; return Ok(APIResponse { status: StatusCode::OK, body: json!({ "message": "User settings saved successfully" }), }); } - + async fn get_user_settings( &self, req: &ParsedRequest, @@ -377,30 +422,36 @@ impl APIHandler { // Early return if `deviceToken` is missing let device_token = match url_params.get("deviceToken") { Some(token) => token, - None => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "deviceToken is required on the URL" }), - }), + None => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "deviceToken is required on the URL" }), + }) + } }; - + // Early return if `pubkey` is missing let pubkey = match url_params.get("pubkey") { Some(key) => key, - None => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "pubkey is required on the URL" }), - }), + None => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "pubkey is required on the URL" }), + }) + } }; - + // Validate the `pubkey` and prepare it for use let pubkey = match nostr::PublicKey::from_hex(pubkey) { Ok(key) => key, - Err(_) => return Ok(APIResponse { - status: StatusCode::BAD_REQUEST, - body: json!({ "error": "Invalid pubkey" }), - }), + Err(_) => { + return Ok(APIResponse { + status: StatusCode::BAD_REQUEST, + body: json!({ "error": "Invalid pubkey" }), + }) + } }; - + // Early return if `pubkey` does not match `req.authorized_pubkey` if pubkey != req.authorized_pubkey { return Ok(APIResponse { @@ -408,10 +459,13 @@ impl APIHandler { body: json!({ "error": "Forbidden" }), }); } - + // Proceed with the main logic after passing all checks - let settings = self.notification_manager.get_user_notification_settings(&req.authorized_pubkey, device_token.to_string()).await?; - + let settings = self + .notification_manager + .get_user_notification_settings(&req.authorized_pubkey, device_token.to_string()) + .await?; + Ok(APIResponse { status: StatusCode::OK, body: json!(settings), @@ -462,10 +516,14 @@ struct APIResponse { } // MARK: - Helper functions - + /// Matches the request to a specified route, returning a hashmap of the route parameters /// e.g. GET /user/:id/info route against request GET /user/123/info matches to { "id": "123" } -fn route_match<'a>(method: &Method, path: &'a str, req: &ParsedRequest) -> Option> { +fn route_match<'a>( + method: &Method, + path: &'a str, + req: &ParsedRequest, +) -> Option> { if method != req.method { return None; } diff --git a/src/nip98_auth.rs b/src/nip98_auth.rs index 9c83d7b..e7a0847 100644 --- a/src/nip98_auth.rs +++ b/src/nip98_auth.rs @@ -1,10 +1,10 @@ +use super::utils::time_delta::TimeDelta; use base64::prelude::*; use nostr; use nostr::bitcoin::hashes::sha256::Hash as Sha256Hash; use nostr::bitcoin::hashes::Hash; use nostr::util::hex; use serde_json::Value; -use super::utils::time_delta::TimeDelta; pub async fn nip98_verify_auth_header( auth_header: String, diff --git a/src/notepush_env.rs b/src/notepush_env.rs index 3f40f98..9d78804 100644 --- a/src/notepush_env.rs +++ b/src/notepush_env.rs @@ -54,7 +54,9 @@ impl NotePushEnv { .unwrap_or(DEFAULT_NOSTR_EVENT_CACHE_MAX_AGE.to_string()) .parse::() .map(|s| std::time::Duration::from_secs(s)) - .unwrap_or(std::time::Duration::from_secs(DEFAULT_NOSTR_EVENT_CACHE_MAX_AGE)); + .unwrap_or(std::time::Duration::from_secs( + DEFAULT_NOSTR_EVENT_CACHE_MAX_AGE, + )); Ok(NotePushEnv { apns_private_key_path, @@ -67,7 +69,7 @@ impl NotePushEnv { port, api_base_url, relay_url, - nostr_event_cache_max_age + nostr_event_cache_max_age, }) } diff --git a/src/notification_manager/mod.rs b/src/notification_manager/mod.rs index a62a9b9..ea72b0a 100644 --- a/src/notification_manager/mod.rs +++ b/src/notification_manager/mod.rs @@ -1,6 +1,6 @@ -pub mod nostr_network_helper; -mod nostr_event_extensions; mod nostr_event_cache; +mod nostr_event_extensions; +pub mod nostr_network_helper; pub mod notification_manager; pub mod utils; diff --git a/src/notification_manager/nostr_event_cache.rs b/src/notification_manager/nostr_event_cache.rs index 2b1cfdc..6e12284 100644 --- a/src/notification_manager/nostr_event_cache.rs +++ b/src/notification_manager/nostr_event_cache.rs @@ -1,13 +1,16 @@ -use crate::{notification_manager::nostr_event_extensions::MaybeConvertibleToTimestampedMuteList, utils::time_delta::TimeDelta}; -use tokio::time::{Duration, Instant}; +use super::nostr_event_extensions::{MaybeConvertibleToRelayList, RelayList, TimestampedMuteList}; +use crate::{ + notification_manager::nostr_event_extensions::MaybeConvertibleToTimestampedMuteList, + utils::time_delta::TimeDelta, +}; +use log; use nostr_sdk::prelude::*; use std::collections::HashMap; -use log; use std::str::FromStr; -use super::nostr_event_extensions::{MaybeConvertibleToRelayList, RelayList, TimestampedMuteList}; +use tokio::time::{Duration, Instant}; struct CacheEntry { - value: Option, // `None` means the event does not exist as far as we know (It does NOT mean expired) + value: Option, // `None` means the event does not exist as far as we know (It does NOT mean expired) added_at: Instant, } @@ -18,7 +21,10 @@ impl CacheEntry { pub fn new(value: T) -> Self { let added_at = Instant::now(); - CacheEntry { value: Some(value), added_at } + CacheEntry { + value: Some(value), + added_at, + } } pub fn maybe(value: Option) -> Self { @@ -28,7 +34,10 @@ impl CacheEntry { pub fn empty() -> Self { let added_at = Instant::now(); - CacheEntry { value: None, added_at } + CacheEntry { + value: None, + added_at, + } } pub fn value(&self) -> Option<&T> { @@ -44,12 +53,21 @@ pub struct Cache { max_age: Duration, } -fn get_cache_entry(list: &mut HashMap>, pubkey: &PublicKey, max_age: Duration, name: &str) -> Result, CacheError> { +fn get_cache_entry( + list: &mut HashMap>, + pubkey: &PublicKey, + max_age: Duration, + name: &str, +) -> Result, CacheError> { let res = if let Some(entry) = list.get(pubkey) { if !entry.is_expired(max_age) { Ok(entry.value().cloned()) } else { - log::debug!("{} list for pubkey {} is expired, removing it from the cache", name, pubkey.to_hex()); + log::debug!( + "{} list for pubkey {} is expired, removing it from the cache", + name, + pubkey.to_hex() + ); Err(CacheError::Expired) } } else { @@ -78,62 +96,90 @@ impl Cache { // MARK: - Adding items to the cache - pub fn add_optional_mute_list_with_author<'a>(&'a mut self, author: &PublicKey, mute_list: Option<&Event>) { + pub fn add_optional_mute_list_with_author<'a>( + &'a mut self, + author: &PublicKey, + mute_list: Option<&Event>, + ) { if let Some(mute_list) = mute_list { self.add_event(mute_list); } else { - self.mute_lists.insert( - author.to_owned(), - CacheEntry::empty(), - ); + self.mute_lists + .insert(author.to_owned(), CacheEntry::empty()); } } - pub fn add_optional_relay_list_with_author<'a>(&'a mut self, author: &PublicKey, relay_list_event: Option<&Event>) { + pub fn add_optional_relay_list_with_author<'a>( + &'a mut self, + author: &PublicKey, + relay_list_event: Option<&Event>, + ) { if let Some(relay_list_event) = relay_list_event { self.add_event(relay_list_event); } else { - self.relay_lists.insert( - author.to_owned(), - CacheEntry::empty(), - ); + self.relay_lists + .insert(author.to_owned(), CacheEntry::empty()); } } - pub fn add_optional_contact_list_with_author<'a>(&'a mut self, author: &PublicKey, contact_list: Option<&Event>) { + pub fn add_optional_contact_list_with_author<'a>( + &'a mut self, + author: &PublicKey, + contact_list: Option<&Event>, + ) { if let Some(contact_list) = contact_list { self.add_event(contact_list); } else { - self.contact_lists.insert( - author.to_owned(), - CacheEntry::empty(), - ); + self.contact_lists + .insert(author.to_owned(), CacheEntry::empty()); } } pub fn add_event(&mut self, event: &Event) { match event.kind { Kind::MuteList => { - self.mute_lists.insert(event.pubkey.clone(), CacheEntry::maybe(event.to_timestamped_mute_list())); - log::debug!("Added mute list to the cache. Event ID: {}", event.id.to_hex()); + self.mute_lists.insert( + event.pubkey.clone(), + CacheEntry::maybe(event.to_timestamped_mute_list()), + ); + log::debug!( + "Added mute list to the cache. Event ID: {}", + event.id.to_hex() + ); } Kind::ContactList => { - log::debug!("Added contact list to the cache. Event ID: {}", event.id.to_hex()); - self.contact_lists.insert(event.pubkey.clone(), CacheEntry::new(event.to_owned())); - }, + log::debug!( + "Added contact list to the cache. Event ID: {}", + event.id.to_hex() + ); + self.contact_lists + .insert(event.pubkey.clone(), CacheEntry::new(event.to_owned())); + } Kind::RelayList => { - log::debug!("Added relay list to the cache. Event ID: {}", event.id.to_hex()); - self.relay_lists.insert(event.pubkey.clone(), CacheEntry::maybe(event.to_relay_list())); - }, + log::debug!( + "Added relay list to the cache. Event ID: {}", + event.id.to_hex() + ); + self.relay_lists.insert( + event.pubkey.clone(), + CacheEntry::maybe(event.to_relay_list()), + ); + } _ => { - log::debug!("Unknown event kind, not adding to any cache. Event ID: {}", event.id.to_hex()); + log::debug!( + "Unknown event kind, not adding to any cache. Event ID: {}", + event.id.to_hex() + ); } } } // MARK: - Fetching items from the cache - pub fn get_mute_list(&mut self, pubkey: &PublicKey) -> Result, CacheError> { + pub fn get_mute_list( + &mut self, + pubkey: &PublicKey, + ) -> Result, CacheError> { get_cache_entry(&mut self.mute_lists, pubkey, self.max_age, "Mute") } @@ -163,7 +209,9 @@ mod tests { // Helper function to create a dummy event of a given kind for testing. fn create_dummy_event(pubkey: PublicKey, kind: Kind) -> Event { // In a real test, you might generate keys or events more dynamically. - let id = EventId::from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap(); + let id = + EventId::from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + .unwrap(); let created_at = Timestamp::now(); let content = ""; let sig_str = "8e1a61523765a6e577e3ca0c87afe3694ed518719aea067701c35262dd2a3c7e3ca0946fe98463a3af706dd333695ceec6cb3b29254c557c8630d3db1171ea3d"; @@ -175,7 +223,8 @@ mod tests { // Helper function to create a dummy public key for testing. fn create_dummy_pubkey() -> PublicKey { // In a real project, you'd generate a key. For the sake of tests, just parse a known hex. - PublicKey::from_hex("32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245").unwrap() + PublicKey::from_hex("32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245") + .unwrap() } #[tokio::test] @@ -185,7 +234,10 @@ mod tests { let mut cache = Cache::new(max_age); // Initially, no contact list should be found. - assert!(matches!(cache.get_contact_list(&pubkey), Err(CacheError::NotFound))); + assert!(matches!( + cache.get_contact_list(&pubkey), + Err(CacheError::NotFound) + )); // Add a contact list event. let event = create_dummy_event(pubkey, Kind::ContactList); @@ -205,7 +257,10 @@ mod tests { let mut cache = Cache::new(max_age); // No mute list initially - assert!(matches!(cache.get_mute_list(&pubkey), Err(CacheError::NotFound))); + assert!(matches!( + cache.get_mute_list(&pubkey), + Err(CacheError::NotFound) + )); // Add a mute list event. let mutelist_event = { @@ -225,7 +280,10 @@ mod tests { let mut cache = Cache::new(max_age); // No relay list initially - assert!(matches!(cache.get_relay_list(&pubkey), Err(CacheError::NotFound))); + assert!(matches!( + cache.get_relay_list(&pubkey), + Err(CacheError::NotFound) + )); // Add a relay list event. let relaylist_event = create_dummy_event(pubkey, Kind::RelayList); diff --git a/src/notification_manager/nostr_event_extensions.rs b/src/notification_manager/nostr_event_extensions.rs index 50b3f52..3228c22 100644 --- a/src/notification_manager/nostr_event_extensions.rs +++ b/src/notification_manager/nostr_event_extensions.rs @@ -1,4 +1,10 @@ -use nostr::{self, key::PublicKey, nips::{nip51::MuteList, nip65}, Alphabet, SingleLetterTag, TagKind::SingleLetter}; +use nostr::{ + self, + key::PublicKey, + nips::{nip51::MuteList, nip65}, + Alphabet, SingleLetterTag, + TagKind::SingleLetter, +}; use nostr_sdk::{EventId, Kind, TagKind}; /// Temporary scaffolding of old methods that have not been ported to use native Event methods @@ -104,10 +110,26 @@ impl MaybeConvertibleToMuteList for nostr::Event { return None; } Some(MuteList { - public_keys: self.referenced_pubkeys().iter().map(|pk| pk.clone()).collect(), - hashtags: self.referenced_hashtags().iter().map(|tag| tag.clone()).collect(), - event_ids: self.referenced_event_ids().iter().map(|id| id.clone()).collect(), - words: self.get_tags_content(TagKind::Word).iter().map(|tag| tag.to_string()).collect(), + public_keys: self + .referenced_pubkeys() + .iter() + .map(|pk| pk.clone()) + .collect(), + hashtags: self + .referenced_hashtags() + .iter() + .map(|tag| tag.clone()) + .collect(), + event_ids: self + .referenced_event_ids() + .iter() + .map(|id| id.clone()) + .collect(), + words: self + .get_tags_content(TagKind::Word) + .iter() + .map(|tag| tag.to_string()) + .collect(), }) } } @@ -138,7 +160,8 @@ impl MaybeConvertibleToRelayList for nostr::Event { } let extracted_relay_list = nip65::extract_relay_list(&self); // Convert the extracted relay list data fully into owned data that can be returned - let extracted_relay_list_owned = extracted_relay_list.into_iter() + let extracted_relay_list_owned = extracted_relay_list + .into_iter() .map(|(url, metadata)| (url.clone(), metadata.as_ref().map(|m| m.clone()))) .collect(); @@ -167,45 +190,60 @@ impl Codable for MuteList { fn from_json(json: serde_json::Value) -> Result> where - Self: Sized { - let public_keys = json.get("public_keys") - .ok_or_else(|| "Missing 'public_keys' field".to_string())? - .as_array() - .ok_or_else(|| "'public_keys' must be an array".to_string())? - .iter() - .map(|pk| PublicKey::from_hex(pk.as_str().unwrap_or_default()).map_err(|e| e.to_string())) - .collect::, String>>()?; - - let hashtags = json.get("hashtags") - .ok_or_else(|| "Missing 'hashtags' field".to_string())? - .as_array() - .ok_or_else(|| "'hashtags' must be an array".to_string())? - .iter() - .map(|tag| tag.as_str().map(|s| s.to_string()).ok_or_else(|| "Invalid hashtag".to_string())) - .collect::, String>>()?; - - let event_ids = json.get("event_ids") - .ok_or_else(|| "Missing 'event_ids' field".to_string())? - .as_array() - .ok_or_else(|| "'event_ids' must be an array".to_string())? - .iter() - .map(|id| EventId::from_hex(id.as_str().unwrap_or_default()).map_err(|e| e.to_string())) - .collect::, String>>()?; - - let words = json.get("words") - .ok_or_else(|| "Missing 'words' field".to_string())? - .as_array() - .ok_or_else(|| "'words' must be an array".to_string())? - .iter() - .map(|word| word.as_str().map(|s| s.to_string()).ok_or_else(|| "Invalid word".to_string())) - .collect::, String>>()?; - - Ok(MuteList { - public_keys, - hashtags, - event_ids, - words, + Self: Sized, + { + let public_keys = json + .get("public_keys") + .ok_or_else(|| "Missing 'public_keys' field".to_string())? + .as_array() + .ok_or_else(|| "'public_keys' must be an array".to_string())? + .iter() + .map(|pk| { + PublicKey::from_hex(pk.as_str().unwrap_or_default()).map_err(|e| e.to_string()) }) + .collect::, String>>()?; + + let hashtags = json + .get("hashtags") + .ok_or_else(|| "Missing 'hashtags' field".to_string())? + .as_array() + .ok_or_else(|| "'hashtags' must be an array".to_string())? + .iter() + .map(|tag| { + tag.as_str() + .map(|s| s.to_string()) + .ok_or_else(|| "Invalid hashtag".to_string()) + }) + .collect::, String>>()?; + + let event_ids = json + .get("event_ids") + .ok_or_else(|| "Missing 'event_ids' field".to_string())? + .as_array() + .ok_or_else(|| "'event_ids' must be an array".to_string())? + .iter() + .map(|id| EventId::from_hex(id.as_str().unwrap_or_default()).map_err(|e| e.to_string())) + .collect::, String>>()?; + + let words = json + .get("words") + .ok_or_else(|| "Missing 'words' field".to_string())? + .as_array() + .ok_or_else(|| "'words' must be an array".to_string())? + .iter() + .map(|word| { + word.as_str() + .map(|s| s.to_string()) + .ok_or_else(|| "Invalid word".to_string()) + }) + .collect::, String>>()?; + + Ok(MuteList { + public_keys, + hashtags, + event_ids, + words, + }) } } diff --git a/src/notification_manager/nostr_network_helper.rs b/src/notification_manager/nostr_network_helper.rs index 446a034..94534cd 100644 --- a/src/notification_manager/nostr_network_helper.rs +++ b/src/notification_manager/nostr_network_helper.rs @@ -1,9 +1,9 @@ -use tokio::sync::Mutex; +use super::nostr_event_cache::Cache; use super::nostr_event_extensions::{RelayList, TimestampedMuteList}; use super::notification_manager::EventSaver; use super::ExtendedEvent; use nostr_sdk::prelude::*; -use super::nostr_event_cache::Cache; +use tokio::sync::Mutex; use tokio::time::{timeout, Duration}; const NOTE_FETCH_TIMEOUT: Duration = Duration::from_secs(5); @@ -11,13 +11,17 @@ const NOTE_FETCH_TIMEOUT: Duration = Duration::from_secs(5); pub struct NostrNetworkHelper { bootstrap_client: Client, cache: Mutex, - event_saver: EventSaver + event_saver: EventSaver, } impl NostrNetworkHelper { // MARK: - Initialization - pub async fn new(relay_url: String, cache_max_age: Duration, event_saver: EventSaver) -> Result> { + pub async fn new( + relay_url: String, + cache_max_age: Duration, + event_saver: EventSaver, + ) -> Result> { let client = Client::new(&Keys::generate()); client.add_relay(relay_url.clone()).await?; client.connect().await; @@ -54,7 +58,7 @@ impl NostrNetworkHelper { if let Ok(optional_mute_list) = cache_mutex_guard.get_mute_list(pubkey) { return optional_mute_list; } - } // Release the lock here for improved performance + } // Release the lock here for improved performance // We don't have an answer from the cache, so we need to fetch it let mute_list_event = self.fetch_single_event(pubkey, Kind::MuteList).await; @@ -69,10 +73,15 @@ impl NostrNetworkHelper { if let Ok(optional_relay_list) = cache_mutex_guard.get_relay_list(pubkey) { return optional_relay_list; } - } // Release the lock here for improved performance + } // Release the lock here for improved performance // We don't have an answer from the cache, so we need to fetch it - let relay_list_event = NostrNetworkHelper::fetch_single_event_from_client(pubkey, Kind::RelayList, &self.bootstrap_client).await; + let relay_list_event = NostrNetworkHelper::fetch_single_event_from_client( + pubkey, + Kind::RelayList, + &self.bootstrap_client, + ) + .await; let mut cache_mutex_guard = self.cache.lock().await; cache_mutex_guard.add_optional_relay_list_with_author(pubkey, relay_list_event.as_ref()); cache_mutex_guard.get_relay_list(pubkey).ok()? @@ -84,12 +93,13 @@ impl NostrNetworkHelper { if let Ok(optional_contact_list) = cache_mutex_guard.get_contact_list(pubkey) { return optional_contact_list; } - } // Release the lock here for improved performance + } // Release the lock here for improved performance // We don't have an answer from the cache, so we need to fetch it let contact_list_event = self.fetch_single_event(pubkey, Kind::ContactList).await; let mut cache_mutex_guard = self.cache.lock().await; - cache_mutex_guard.add_optional_contact_list_with_author(pubkey, contact_list_event.as_ref()); + cache_mutex_guard + .add_optional_contact_list_with_author(pubkey, contact_list_event.as_ref()); cache_mutex_guard.get_contact_list(pubkey).ok()? } @@ -99,15 +109,24 @@ impl NostrNetworkHelper { let event = match self.make_client_for(author).await { Some(client) => { NostrNetworkHelper::fetch_single_event_from_client(author, kind, &client).await - }, + } None => { - NostrNetworkHelper::fetch_single_event_from_client(author, kind, &self.bootstrap_client).await - }, + NostrNetworkHelper::fetch_single_event_from_client( + author, + kind, + &self.bootstrap_client, + ) + .await + } }; // Save event to our database if needed if let Some(event) = event.clone() { if let Err(error) = self.event_saver.save_if_needed(&event).await { - log::warn!("Failed to save event '{:?}'. Error: {:?}", event.id.to_hex(), error) + log::warn!( + "Failed to save event '{:?}'. Error: {:?}", + event.id.to_hex(), + error + ) } } event @@ -118,7 +137,8 @@ impl NostrNetworkHelper { let relay_list = self.get_relay_list(author).await?; for (url, metadata) in relay_list { - if metadata.map_or(true, |m| m == RelayMetadata::Write) { // Only add "write" relays, as per NIP-65 spec on reading data FROM user + if metadata.map_or(true, |m| m == RelayMetadata::Write) { + // Only add "write" relays, as per NIP-65 spec on reading data FROM user if let Err(e) = client.add_relay(url.clone()).await { log::warn!("Failed to add relay URL: {:?}, error: {:?}", url, e); } @@ -130,7 +150,11 @@ impl NostrNetworkHelper { Some(client) } - async fn fetch_single_event_from_client(author: &PublicKey, kind: Kind, client: &Client) -> Option { + async fn fetch_single_event_from_client( + author: &PublicKey, + kind: Kind, + client: &Client, + ) -> Option { let subscription_filter = Filter::new() .kinds(vec![kind]) .authors(vec![author.clone()]) diff --git a/src/notification_manager/notification_manager.rs b/src/notification_manager/notification_manager.rs index 15f753a..cc4c82f 100644 --- a/src/notification_manager/notification_manager.rs +++ b/src/notification_manager/notification_manager.rs @@ -10,10 +10,10 @@ use rusqlite; use rusqlite::params; use serde::Deserialize; use serde::Serialize; -use tokio::sync::Mutex; use std::collections::HashSet; use std::sync::Arc; use tokio; +use tokio::sync::Mutex; use super::nostr_event_extensions::Codable; use super::nostr_event_extensions::MaybeConvertibleToMuteList; @@ -34,12 +34,12 @@ pub struct NotificationManager { apns_topic: String, apns_client: Mutex, nostr_network_helper: NostrNetworkHelper, - pub event_saver: EventSaver + pub event_saver: EventSaver, } #[derive(Clone)] pub struct EventSaver { - db: Arc>> + db: Arc>>, } impl EventSaver { @@ -47,32 +47,46 @@ impl EventSaver { Self { db } } - pub async fn save_if_needed(&self, event: &nostr::Event) -> Result> { + pub async fn save_if_needed( + &self, + event: &nostr::Event, + ) -> Result> { match event.to_mute_list() { Some(mute_list) => { - match self.get_saved_mute_list_for(event.author()).await.ok().flatten() { + match self + .get_saved_mute_list_for(event.author()) + .await + .ok() + .flatten() + { Some(saved_timestamped_mute_list) => { let saved_mute_list_timestamp = saved_timestamped_mute_list.timestamp; if saved_mute_list_timestamp < event.created_at() { - self.save_mute_list(event.author(), mute_list, event.created_at).await?; + self.save_mute_list(event.author(), mute_list, event.created_at) + .await?; + } else { + return Ok(false); } - else { - return Ok(false) - } - }, + } None => { - self.save_mute_list(event.author(), mute_list, event.created_at).await?; + self.save_mute_list(event.author(), mute_list, event.created_at) + .await?; } } Ok(true) - }, + } None => Ok(false), } } // MARK: - Muting preferences - pub async fn save_mute_list(&self, pubkey: PublicKey, mute_list: MuteList, created_at: Timestamp) -> Result<(), Box> { + pub async fn save_mute_list( + &self, + pubkey: PublicKey, + mute_list: MuteList, + created_at: Timestamp, + ) -> Result<(), Box> { let mute_list_json = mute_list.to_json()?; let db_mutex_guard = self.db.lock().await; let connection = db_mutex_guard.get()?; @@ -92,7 +106,10 @@ impl EventSaver { Ok(()) } - pub async fn get_saved_mute_list_for(&self, pubkey: PublicKey) -> Result, Box> { + pub async fn get_saved_mute_list_for( + &self, + pubkey: PublicKey, + ) -> Result, Box> { let db_mutex_guard = self.db.lock().await; let connection = db_mutex_guard.get()?; @@ -100,7 +117,10 @@ impl EventSaver { "SELECT mute_list, created_at FROM muting_preferences WHERE user_pubkey = ?", )?; - let mute_list_info: (serde_json::Value, nostr::Timestamp) = match stmt.query_row([pubkey.to_sql_string()], |row| { Ok((row.get(0)?, row.get(1)?)) }) { + let mute_list_info: (serde_json::Value, nostr::Timestamp) = match stmt + .query_row([pubkey.to_sql_string()], |row| { + Ok((row.get(0)?, row.get(1)?)) + }) { Ok(info) => (info.0, nostr::Timestamp::from_sql_string(info.1)?), Err(rusqlite::Error::QueryReturnedNoRows) => return Ok(None), Err(e) => return Err(e.into()), @@ -109,7 +129,7 @@ impl EventSaver { let mute_list = MuteList::from_json(mute_list_info.0)?; let timestamped_mute_list = TimestampedMuteList { mute_list, - timestamp: mute_list_info.1 + timestamp: mute_list_info.1, }; Ok(Some(timestamped_mute_list)) @@ -148,7 +168,12 @@ impl NotificationManager { db, apns_topic, apns_client: Mutex::new(client), - nostr_network_helper: NostrNetworkHelper::new(relay_url.clone(), cache_max_age, event_saver.clone()).await?, + nostr_network_helper: NostrNetworkHelper::new( + relay_url.clone(), + cache_max_age, + event_saver.clone(), + ) + .await?, event_saver, }; @@ -194,12 +219,48 @@ impl NotificationManager { // Notification settings migration (https://github.com/damus-io/damus/issues/2360) - Self::add_column_if_not_exists(&db, "user_info", "zap_notifications_enabled", "BOOLEAN", Some("true"))?; - Self::add_column_if_not_exists(&db, "user_info", "mention_notifications_enabled", "BOOLEAN", Some("true"))?; - Self::add_column_if_not_exists(&db, "user_info", "repost_notifications_enabled", "BOOLEAN", Some("true"))?; - Self::add_column_if_not_exists(&db, "user_info", "reaction_notifications_enabled", "BOOLEAN", Some("true"))?; - Self::add_column_if_not_exists(&db, "user_info", "dm_notifications_enabled", "BOOLEAN", Some("true"))?; - Self::add_column_if_not_exists(&db, "user_info", "only_notifications_from_following_enabled", "BOOLEAN", Some("false"))?; + Self::add_column_if_not_exists( + &db, + "user_info", + "zap_notifications_enabled", + "BOOLEAN", + Some("true"), + )?; + Self::add_column_if_not_exists( + &db, + "user_info", + "mention_notifications_enabled", + "BOOLEAN", + Some("true"), + )?; + Self::add_column_if_not_exists( + &db, + "user_info", + "repost_notifications_enabled", + "BOOLEAN", + Some("true"), + )?; + Self::add_column_if_not_exists( + &db, + "user_info", + "reaction_notifications_enabled", + "BOOLEAN", + Some("true"), + )?; + Self::add_column_if_not_exists( + &db, + "user_info", + "dm_notifications_enabled", + "BOOLEAN", + Some("true"), + )?; + Self::add_column_if_not_exists( + &db, + "user_info", + "only_notifications_from_following_enabled", + "BOOLEAN", + Some("false"), + )?; // Migration related to mute list improvements (https://github.com/damus-io/damus/issues/2118) @@ -232,7 +293,10 @@ impl NotificationManager { if !column_names.contains(&column_name.to_string()) { let query = format!( "ALTER TABLE {} ADD COLUMN {} {} {}", - table_name, column_name, column_type, match default_value { + table_name, + column_name, + column_type, + match default_value { Some(value) => format!("DEFAULT {}", value), None => "".to_string(), }, @@ -319,12 +383,12 @@ impl NotificationManager { } let pubkeys_that_received_notification = notification_status.pubkeys_that_received_notification(); - let relevant_pubkeys_yet_to_receive: HashSet = relevant_pubkeys_that_are_registered - .difference(&pubkeys_that_received_notification) - .filter(|&x| *x != event.pubkey) - .cloned() - .collect(); - + let relevant_pubkeys_yet_to_receive: HashSet = + relevant_pubkeys_that_are_registered + .difference(&pubkeys_that_received_notification) + .filter(|&x| *x != event.pubkey) + .cloned() + .collect(); let mut pubkeys_to_notify = HashSet::new(); for pubkey in relevant_pubkeys_yet_to_receive { @@ -340,39 +404,49 @@ impl NotificationManager { } async fn should_mute_notification_for_pubkey(&self, event: &Event, pubkey: &PublicKey) -> bool { - let latest_mute_list = self.get_newest_mute_list_available(pubkey).await.ok().flatten(); + let latest_mute_list = self + .get_newest_mute_list_available(pubkey) + .await + .ok() + .flatten(); if let Some(latest_mute_list) = latest_mute_list { - return should_mute_notification_for_mutelist(event, &latest_mute_list) + return should_mute_notification_for_mutelist(event, &latest_mute_list); } - return false + return false; } - async fn get_newest_mute_list_available(&self, pubkey: &PublicKey) -> Result, Box> { + async fn get_newest_mute_list_available( + &self, + pubkey: &PublicKey, + ) -> Result, Box> { let timestamped_saved_mute_list = self.event_saver.get_saved_mute_list_for(*pubkey).await?; - let timestamped_network_mute_list = self.nostr_network_helper.get_public_mute_list(pubkey).await; - Ok(match (timestamped_saved_mute_list, timestamped_network_mute_list) { - (Some(local_mute), Some(network_mute)) => { - if local_mute.timestamp > network_mute.timestamp { - log::debug!("Mute lists available in both database and from the network for pubkey {}. Using local mute list since it's newer.", pubkey.to_hex()); + let timestamped_network_mute_list = + self.nostr_network_helper.get_public_mute_list(pubkey).await; + Ok( + match (timestamped_saved_mute_list, timestamped_network_mute_list) { + (Some(local_mute), Some(network_mute)) => { + if local_mute.timestamp > network_mute.timestamp { + log::debug!("Mute lists available in both database and from the network for pubkey {}. Using local mute list since it's newer.", pubkey.to_hex()); + Some(local_mute.mute_list) + } else { + log::debug!("Mute lists available in both database and from the network for pubkey {}. Using network mute list since it's newer.", pubkey.to_hex()); + Some(network_mute.mute_list) + } + } + (Some(local_mute), None) => { + log::debug!("Mute list available in database for pubkey {}, but not from the network. Using local mute list.", pubkey.to_hex()); Some(local_mute.mute_list) - } else { - log::debug!("Mute lists available in both database and from the network for pubkey {}. Using network mute list since it's newer.", pubkey.to_hex()); + } + (None, Some(network_mute)) => { + log::debug!("Mute list for pubkey {} available from the network, but not in the database. Using network mute list.", pubkey.to_hex()); Some(network_mute.mute_list) } + (None, None) => { + log::debug!("No mute list available for pubkey {}", pubkey.to_hex()); + None + } }, - (Some(local_mute), None) => { - log::debug!("Mute list available in database for pubkey {}, but not from the network. Using local mute list.", pubkey.to_hex()); - Some(local_mute.mute_list) - }, - (None, Some(network_mute)) => { - log::debug!("Mute list for pubkey {} available from the network, but not in the database. Using network mute list.", pubkey.to_hex()); - Some(network_mute.mute_list) - }, - (None, None) => { - log::debug!("No mute list available for pubkey {}", pubkey.to_hex()); - None - }, - }) + ) } async fn pubkeys_relevant_to_event( @@ -382,8 +456,9 @@ impl NotificationManager { let mut relevant_pubkeys = event.relevant_pubkeys(); let referenced_event_ids = event.referenced_event_ids(); for referenced_event_id in referenced_event_ids { - let pubkeys_relevant_to_referenced_event = - self.pubkeys_subscribed_to_event_id(&referenced_event_id).await?; + let pubkeys_relevant_to_referenced_event = self + .pubkeys_subscribed_to_event_id(&referenced_event_id) + .await?; relevant_pubkeys.extend(pubkeys_relevant_to_referenced_event); } Ok(relevant_pubkeys) @@ -411,7 +486,10 @@ impl NotificationManager { ) -> Result<(), Box> { let user_device_tokens = self.get_user_device_tokens(pubkey).await?; for device_token in user_device_tokens { - if !self.user_wants_notification(pubkey, device_token.clone(), event).await? { + if !self + .user_wants_notification(pubkey, device_token.clone(), event) + .await? + { continue; } self.send_event_notification_to_device_token(event, &device_token) @@ -426,14 +504,20 @@ impl NotificationManager { device_token: String, event: &Event, ) -> Result> { - let notification_preferences = self.get_user_notification_settings(pubkey, device_token).await?; + let notification_preferences = self + .get_user_notification_settings(pubkey, device_token) + .await?; if notification_preferences.only_notifications_from_following_enabled { - if !self.nostr_network_helper.does_pubkey_follow_pubkey(pubkey, &event.author()).await { + if !self + .nostr_network_helper + .does_pubkey_follow_pubkey(pubkey, &event.author()) + .await + { return Ok(false); } } match event.kind { - Kind::TextNote => Ok(notification_preferences.mention_notifications_enabled), // TODO: Not 100% accurate + Kind::TextNote => Ok(notification_preferences.mention_notifications_enabled), // TODO: Not 100% accurate Kind::EncryptedDirectMessage => Ok(notification_preferences.dm_notifications_enabled), Kind::Repost => Ok(notification_preferences.repost_notifications_enabled), Kind::GenericRepost => Ok(notification_preferences.repost_notifications_enabled), @@ -523,14 +607,20 @@ impl NotificationManager { .build(device_token, Default::default()); payload.options.apns_topic = Some(self.apns_topic.as_str()); - payload.data.insert("nostr_event", serde_json::Value::String(event.try_as_json()?)); - + payload.data.insert( + "nostr_event", + serde_json::Value::String(event.try_as_json()?), + ); let apns_client_mutex_guard = self.apns_client.lock().await; match apns_client_mutex_guard.send(payload).await { - Ok(_response) => {}, - Err(e) => log::error!("Failed to send notification to device token '{}': {}", device_token, e), + Ok(_response) => {} + Err(e) => log::error!( + "Failed to send notification to device token '{}': {}", + device_token, + e + ), } log::info!("Notification sent to device token: {}", device_token); @@ -542,7 +632,10 @@ impl NotificationManager { // NOTE: This is simple because the client will handle formatting. These are just fallbacks. let (title, body) = match event.kind { nostr_sdk::Kind::TextNote => ("New activity".to_string(), event.content.clone()), - nostr_sdk::Kind::EncryptedDirectMessage => ("New direct message".to_string(), "Contents are encrypted".to_string()), + nostr_sdk::Kind::EncryptedDirectMessage => ( + "New direct message".to_string(), + "Contents are encrypted".to_string(), + ), nostr_sdk::Kind::Repost => ("Someone reposted".to_string(), event.content.clone()), nostr_sdk::Kind::Reaction => { let content_text = event.content.clone(); @@ -553,8 +646,11 @@ impl NotificationManager { _ => content_text.as_str(), }; ("New reaction".to_string(), formatted_text.to_string()) - }, - nostr_sdk::Kind::ZapPrivateMessage => ("New zap private message".to_string(), "Contents are encrypted".to_string()), + } + nostr_sdk::Kind::ZapPrivateMessage => ( + "New zap private message".to_string(), + "Contents are encrypted".to_string(), + ), nostr_sdk::Kind::ZapReceipt => ("Someone zapped you".to_string(), "".to_string()), _ => ("New activity".to_string(), "".to_string()), }; @@ -568,7 +664,10 @@ impl NotificationManager { pubkey: nostr::PublicKey, device_token: &str, ) -> Result<(), Box> { - if self.is_pubkey_token_pair_registered(&pubkey, &device_token).await? { + if self + .is_pubkey_token_pair_registered(&pubkey, &device_token) + .await? + { return Ok(()); } self.save_user_device_info(pubkey, device_token).await @@ -616,17 +715,16 @@ impl NotificationManager { let mut stmt = connection.prepare( "SELECT zap_notifications_enabled, mention_notifications_enabled, repost_notifications_enabled, reaction_notifications_enabled, dm_notifications_enabled, only_notifications_from_following_enabled FROM user_info WHERE pubkey = ? AND device_token = ?", )?; - let settings = stmt - .query_row([pubkey.to_sql_string(), device_token], |row| { - Ok(UserNotificationSettings { - zap_notifications_enabled: row.get(0)?, - mention_notifications_enabled: row.get(1)?, - repost_notifications_enabled: row.get(2)?, - reaction_notifications_enabled: row.get(3)?, - dm_notifications_enabled: row.get(4)?, - only_notifications_from_following_enabled: row.get(5)?, - }) - })?; + let settings = stmt.query_row([pubkey.to_sql_string(), device_token], |row| { + Ok(UserNotificationSettings { + zap_notifications_enabled: row.get(0)?, + mention_notifications_enabled: row.get(1)?, + repost_notifications_enabled: row.get(2)?, + reaction_notifications_enabled: row.get(3)?, + dm_notifications_enabled: row.get(4)?, + only_notifications_from_following_enabled: row.get(5)?, + }) + })?; Ok(settings) } @@ -663,7 +761,7 @@ pub struct UserNotificationSettings { repost_notifications_enabled: bool, reaction_notifications_enabled: bool, dm_notifications_enabled: bool, - only_notifications_from_following_enabled: bool + only_notifications_from_following_enabled: bool, } struct NotificationStatus { diff --git a/src/notification_manager/utils.rs b/src/notification_manager/utils.rs index bd20d94..e52b313 100644 --- a/src/notification_manager/utils.rs +++ b/src/notification_manager/utils.rs @@ -1,21 +1,15 @@ +use super::nostr_event_extensions::ExtendedEvent; use nostr::nips::nip51::MuteList; use nostr_sdk::Event; -use super::nostr_event_extensions::ExtendedEvent; - -pub fn should_mute_notification_for_mutelist( - event: &Event, - mute_list: &MuteList, - ) -> bool { +pub fn should_mute_notification_for_mutelist(event: &Event, mute_list: &MuteList) -> bool { for muted_public_key in &mute_list.public_keys { if event.pubkey == *muted_public_key { return true; } } for muted_event_id in &mute_list.event_ids { - if event.id == *muted_event_id - || event.referenced_event_ids().contains(&muted_event_id) - { + if event.id == *muted_event_id || event.referenced_event_ids().contains(&muted_event_id) { return true; } } diff --git a/src/relay_connection.rs b/src/relay_connection.rs index fa0f7b9..8e64c87 100644 --- a/src/relay_connection.rs +++ b/src/relay_connection.rs @@ -104,8 +104,13 @@ impl RelayConnection { ClientMessage::Event(event) => { log::info!("Received event with id: {:?}", event.id.to_hex()); log::debug!("Event received: {:?}", event); - self.notification_manager.event_saver.save_if_needed(&event).await?; - self.notification_manager.send_notifications_if_needed(&event).await?; + self.notification_manager + .event_saver + .save_if_needed(&event) + .await?; + self.notification_manager + .send_notifications_if_needed(&event) + .await?; let notice_message = format!("blocked: This relay does not store events"); let response = RelayMessage::Ok { event_id: event.id,