mirror of
https://github.com/nostrlabs-io/notepush.git
synced 2025-06-16 03:48:10 +00:00
Merge pull request #6 from danieldaquino/2024-08-30-fix
Improvements to caching and APNS token error handling
This commit is contained in:
@ -253,7 +253,7 @@ impl APIHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Proceed with the main logic after passing all checks
|
// Proceed with the main logic after passing all checks
|
||||||
self.notification_manager.save_user_device_info(pubkey, device_token).await?;
|
self.notification_manager.save_user_device_info_if_not_present(pubkey, device_token).await?;
|
||||||
Ok(APIResponse {
|
Ok(APIResponse {
|
||||||
status: StatusCode::OK,
|
status: StatusCode::OK,
|
||||||
body: json!({ "message": "User info saved successfully" }),
|
body: json!({ "message": "User info saved successfully" }),
|
||||||
|
@ -40,6 +40,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
env.apns_team_id.clone(),
|
env.apns_team_id.clone(),
|
||||||
env.apns_environment.clone(),
|
env.apns_environment.clone(),
|
||||||
env.apns_topic.clone(),
|
env.apns_topic.clone(),
|
||||||
|
env.nostr_event_cache_max_age,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create notification manager"),
|
.expect("Failed to create notification manager"),
|
||||||
|
@ -6,6 +6,7 @@ const DEFAULT_DB_PATH: &str = "./apns_notifications.db";
|
|||||||
const DEFAULT_HOST: &str = "0.0.0.0";
|
const DEFAULT_HOST: &str = "0.0.0.0";
|
||||||
const DEFAULT_PORT: &str = "8000";
|
const DEFAULT_PORT: &str = "8000";
|
||||||
const DEFAULT_RELAY_URL: &str = "wss://relay.damus.io";
|
const DEFAULT_RELAY_URL: &str = "wss://relay.damus.io";
|
||||||
|
const DEFAULT_NOSTR_EVENT_CACHE_MAX_AGE: u64 = 60 * 60; // 1 hour
|
||||||
|
|
||||||
pub struct NotePushEnv {
|
pub struct NotePushEnv {
|
||||||
// The path to the Apple private key .p8 file
|
// The path to the Apple private key .p8 file
|
||||||
@ -26,6 +27,8 @@ pub struct NotePushEnv {
|
|||||||
pub api_base_url: String, // The base URL of where the API server is hosted for NIP-98 auth checks
|
pub api_base_url: String, // The base URL of where the API server is hosted for NIP-98 auth checks
|
||||||
// The URL of the Nostr relay server to connect to for getting mutelists
|
// The URL of the Nostr relay server to connect to for getting mutelists
|
||||||
pub relay_url: String,
|
pub relay_url: String,
|
||||||
|
// The max age of the Nostr event cache, in seconds
|
||||||
|
pub nostr_event_cache_max_age: std::time::Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotePushEnv {
|
impl NotePushEnv {
|
||||||
@ -47,6 +50,11 @@ impl NotePushEnv {
|
|||||||
_ => a2::client::Endpoint::Sandbox,
|
_ => a2::client::Endpoint::Sandbox,
|
||||||
};
|
};
|
||||||
let apns_topic = env::var("APNS_TOPIC")?;
|
let apns_topic = env::var("APNS_TOPIC")?;
|
||||||
|
let nostr_event_cache_max_age = env::var("NOSTR_EVENT_CACHE_MAX_AGE")
|
||||||
|
.unwrap_or(DEFAULT_NOSTR_EVENT_CACHE_MAX_AGE.to_string())
|
||||||
|
.parse::<u64>()
|
||||||
|
.map(|s| std::time::Duration::from_secs(s))
|
||||||
|
.unwrap_or(std::time::Duration::from_secs(DEFAULT_NOSTR_EVENT_CACHE_MAX_AGE));
|
||||||
|
|
||||||
Ok(NotePushEnv {
|
Ok(NotePushEnv {
|
||||||
apns_private_key_path,
|
apns_private_key_path,
|
||||||
@ -59,6 +67,7 @@ impl NotePushEnv {
|
|||||||
port,
|
port,
|
||||||
api_base_url,
|
api_base_url,
|
||||||
relay_url,
|
relay_url,
|
||||||
|
nostr_event_cache_max_age
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,15 +97,23 @@ impl Cache {
|
|||||||
if let Some(entry) = self.mute_lists.get(pubkey) {
|
if let Some(entry) = self.mute_lists.get(pubkey) {
|
||||||
let entry = entry.clone(); // Clone the Arc to avoid borrowing issues
|
let entry = entry.clone(); // Clone the Arc to avoid borrowing issues
|
||||||
if !entry.is_expired(self.max_age) {
|
if !entry.is_expired(self.max_age) {
|
||||||
if let Some(event) = entry.event.clone() {
|
match &entry.event {
|
||||||
|
Some(event) => {
|
||||||
|
log::debug!("Cached mute list for pubkey {} was found", pubkey.to_hex());
|
||||||
return Ok(event.to_mute_list());
|
return Ok(event.to_mute_list());
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
|
log::debug!("Empty mute list cache entry for pubkey {}", pubkey.to_hex());
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Mute list for pubkey {} is expired, removing it from the cache", pubkey.to_hex());
|
log::debug!("Mute list for pubkey {} is expired, removing it from the cache", pubkey.to_hex());
|
||||||
self.mute_lists.remove(pubkey);
|
self.mute_lists.remove(pubkey);
|
||||||
self.remove_event_from_all_maps(&entry.event);
|
self.remove_event_from_all_maps(&entry.event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log::debug!("Mute list for pubkey {} not found on cache", pubkey.to_hex());
|
||||||
Err(CacheError::NotFound)
|
Err(CacheError::NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ use super::nostr_event_cache::Cache;
|
|||||||
use tokio::time::{timeout, Duration};
|
use tokio::time::{timeout, Duration};
|
||||||
|
|
||||||
const NOTE_FETCH_TIMEOUT: Duration = Duration::from_secs(5);
|
const NOTE_FETCH_TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
const CACHE_MAX_AGE: Duration = Duration::from_secs(60);
|
|
||||||
|
|
||||||
pub struct NostrNetworkHelper {
|
pub struct NostrNetworkHelper {
|
||||||
client: Client,
|
client: Client,
|
||||||
@ -16,12 +15,15 @@ pub struct NostrNetworkHelper {
|
|||||||
impl NostrNetworkHelper {
|
impl NostrNetworkHelper {
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
|
|
||||||
pub async fn new(relay_url: String) -> Result<Self, Box<dyn std::error::Error>> {
|
pub async fn new(relay_url: String, cache_max_age: Duration) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let client = Client::new(&Keys::generate());
|
let client = Client::new(&Keys::generate());
|
||||||
client.add_relay(relay_url.clone()).await?;
|
client.add_relay(relay_url.clone()).await?;
|
||||||
client.connect().await;
|
client.connect().await;
|
||||||
|
|
||||||
Ok(NostrNetworkHelper { client, cache: Mutex::new(Cache::new(CACHE_MAX_AGE)) })
|
Ok(NostrNetworkHelper {
|
||||||
|
client,
|
||||||
|
cache: Mutex::new(Cache::new(cache_max_age)),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Answering questions about a user
|
// MARK: - Answering questions about a user
|
||||||
|
@ -41,6 +41,7 @@ impl NotificationManager {
|
|||||||
apns_team_id: String,
|
apns_team_id: String,
|
||||||
apns_environment: a2::client::Endpoint,
|
apns_environment: a2::client::Endpoint,
|
||||||
apns_topic: String,
|
apns_topic: String,
|
||||||
|
cache_max_age: std::time::Duration,
|
||||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let connection = db.get()?;
|
let connection = db.get()?;
|
||||||
Self::setup_database(&connection)?;
|
Self::setup_database(&connection)?;
|
||||||
@ -58,7 +59,7 @@ impl NotificationManager {
|
|||||||
apns_topic,
|
apns_topic,
|
||||||
apns_client: Mutex::new(client),
|
apns_client: Mutex::new(client),
|
||||||
db: Mutex::new(db),
|
db: Mutex::new(db),
|
||||||
nostr_network_helper: NostrNetworkHelper::new(relay_url.clone()).await?,
|
nostr_network_helper: NostrNetworkHelper::new(relay_url.clone(), cache_max_age).await?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +380,11 @@ impl NotificationManager {
|
|||||||
|
|
||||||
|
|
||||||
let apns_client_mutex_guard = self.apns_client.lock().await;
|
let apns_client_mutex_guard = self.apns_client.lock().await;
|
||||||
let _response = apns_client_mutex_guard.send(payload).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),
|
||||||
|
}
|
||||||
|
|
||||||
log::info!("Notification sent to device token: {}", device_token);
|
log::info!("Notification sent to device token: {}", device_token);
|
||||||
|
|
||||||
@ -392,7 +397,16 @@ impl NotificationManager {
|
|||||||
nostr_sdk::Kind::TextNote => ("New activity".to_string(), event.content.clone()),
|
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::Repost => ("Someone reposted".to_string(), event.content.clone()),
|
||||||
nostr_sdk::Kind::Reaction => ("New reaction".to_string(), event.content.clone()),
|
nostr_sdk::Kind::Reaction => {
|
||||||
|
let content_text = event.content.clone();
|
||||||
|
let formatted_text = match content_text.as_str() {
|
||||||
|
"" => "❤️",
|
||||||
|
"+" => "❤️",
|
||||||
|
"-" => "👎",
|
||||||
|
_ => 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()),
|
nostr_sdk::Kind::ZapReceipt => ("Someone zapped you".to_string(), "".to_string()),
|
||||||
_ => ("New activity".to_string(), "".to_string()),
|
_ => ("New activity".to_string(), "".to_string()),
|
||||||
@ -402,6 +416,17 @@ impl NotificationManager {
|
|||||||
|
|
||||||
// MARK: - User device info and settings
|
// MARK: - User device info and settings
|
||||||
|
|
||||||
|
pub async fn save_user_device_info_if_not_present(
|
||||||
|
&self,
|
||||||
|
pubkey: nostr::PublicKey,
|
||||||
|
device_token: &str,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if self.is_pubkey_registered(&pubkey).await? {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.save_user_device_info(pubkey, device_token).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn save_user_device_info(
|
pub async fn save_user_device_info(
|
||||||
&self,
|
&self,
|
||||||
pubkey: nostr::PublicKey,
|
pubkey: nostr::PublicKey,
|
||||||
|
Reference in New Issue
Block a user