Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit 6205bcb

Browse files
committed
WIP: Notification client
1 parent 328571f commit 6205bcb

File tree

4 files changed

+193
-0
lines changed

4 files changed

+193
-0
lines changed

mutiny-core/src/lib.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ mod networking;
3131
mod node;
3232
pub mod nodemanager;
3333
pub mod nostr;
34+
pub mod notifications;
3435
mod onchain;
3536
mod peermanager;
3637
pub mod redshift;
@@ -52,13 +53,16 @@ pub use crate::ldkstorage::{CHANNEL_MANAGER_KEY, MONITORS_PREFIX_KEY};
5253
use crate::auth::MutinyAuthClient;
5354
use crate::labels::{Contact, LabelStorage};
5455
use crate::nostr::nwc::{NwcProfileTag, SpendingConditions};
56+
use crate::notifications::MutinyNotificationClient;
5557
use crate::storage::{MutinyStorage, DEVICE_ID_KEY, EXPECTED_NETWORK_KEY, NEED_FULL_SYNC_KEY};
5658
use crate::{error::MutinyError, nostr::ReservedProfile};
5759
use crate::{nodemanager::NodeManager, nostr::ProfileType};
5860
use crate::{nostr::NostrManager, utils::sleep};
5961
use ::nostr::key::XOnlyPublicKey;
6062
use ::nostr::{Event, Kind, Metadata};
6163
use bip39::Mnemonic;
64+
use bitcoin::hashes::hex::ToHex;
65+
use bitcoin::hashes::{sha256, Hash};
6266
use bitcoin::secp256k1::PublicKey;
6367
use bitcoin::util::bip32::ExtendedPrivKey;
6468
use bitcoin::Network;
@@ -84,6 +88,7 @@ pub struct MutinyWalletConfig {
8488
auth_client: Option<Arc<MutinyAuthClient>>,
8589
subscription_url: Option<String>,
8690
scorer_url: Option<String>,
91+
notification_url: Option<String>,
8792
do_not_connect_peers: bool,
8893
skip_device_lock: bool,
8994
pub safe_mode: bool,
@@ -101,6 +106,7 @@ impl MutinyWalletConfig {
101106
auth_client: Option<Arc<MutinyAuthClient>>,
102107
subscription_url: Option<String>,
103108
scorer_url: Option<String>,
109+
notification_url: Option<String>,
104110
skip_device_lock: bool,
105111
) -> Self {
106112
Self {
@@ -111,6 +117,7 @@ impl MutinyWalletConfig {
111117
user_esplora_url,
112118
user_rgs_url,
113119
scorer_url,
120+
notification_url,
114121
lsp_url,
115122
auth_client,
116123
subscription_url,
@@ -140,6 +147,7 @@ pub struct MutinyWallet<S: MutinyStorage> {
140147
pub storage: S,
141148
pub node_manager: Arc<NodeManager<S>>,
142149
pub nostr: Arc<NostrManager<S>>,
150+
pub notification_client: Option<Arc<MutinyNotificationClient>>,
143151
}
144152

145153
impl<S: MutinyStorage> MutinyWallet<S> {
@@ -161,6 +169,31 @@ impl<S: MutinyStorage> MutinyWallet<S> {
161169

162170
NodeManager::start_sync(node_manager.clone());
163171

172+
let notification_client = match config.notification_url.clone() {
173+
Some(url) => {
174+
let client = match config.auth_client.clone() {
175+
Some(auth_client) => MutinyNotificationClient::new_authenticated(
176+
auth_client,
177+
url,
178+
node_manager.logger.clone(),
179+
),
180+
None => {
181+
// hash key and use that as identifier
182+
let hash = sha256::Hash::hash(&config.xprivkey.private_key.secret_bytes());
183+
let identifier_key = hash.to_hex();
184+
MutinyNotificationClient::new_unauthenticated(
185+
url,
186+
identifier_key,
187+
node_manager.logger.clone(),
188+
)
189+
}
190+
};
191+
192+
Some(Arc::new(client))
193+
}
194+
None => None,
195+
};
196+
164197
// create nostr manager
165198
let nostr = Arc::new(NostrManager::from_mnemonic(
166199
node_manager.xprivkey,
@@ -173,6 +206,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
173206
storage,
174207
node_manager,
175208
nostr,
209+
notification_client,
176210
};
177211

178212
#[cfg(not(test))]
@@ -606,6 +640,7 @@ mod tests {
606640
None,
607641
None,
608642
None,
643+
None,
609644
false,
610645
);
611646
let mw = MutinyWallet::new(storage.clone(), config)
@@ -636,6 +671,7 @@ mod tests {
636671
None,
637672
None,
638673
None,
674+
None,
639675
false,
640676
);
641677
let mut mw = MutinyWallet::new(storage.clone(), config)
@@ -672,6 +708,7 @@ mod tests {
672708
None,
673709
None,
674710
None,
711+
None,
675712
false,
676713
);
677714
let mut mw = MutinyWallet::new(storage.clone(), config)
@@ -709,6 +746,7 @@ mod tests {
709746
None,
710747
None,
711748
None,
749+
None,
712750
false,
713751
);
714752
let mw = MutinyWallet::new(storage.clone(), config)
@@ -734,6 +772,7 @@ mod tests {
734772
None,
735773
None,
736774
None,
775+
None,
737776
false,
738777
);
739778
let mw2 = MutinyWallet::new(storage2.clone(), config2.clone())

mutiny-core/src/nodemanager.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2692,6 +2692,7 @@ mod tests {
26922692
None,
26932693
None,
26942694
None,
2695+
None,
26952696
false,
26962697
);
26972698
NodeManager::new(c, storage.clone())
@@ -2722,6 +2723,7 @@ mod tests {
27222723
None,
27232724
None,
27242725
None,
2726+
None,
27252727
false,
27262728
);
27272729
let nm = NodeManager::new(c, storage)
@@ -2773,6 +2775,7 @@ mod tests {
27732775
None,
27742776
None,
27752777
None,
2778+
None,
27762779
false,
27772780
);
27782781
let c = c.with_safe_mode();
@@ -2809,6 +2812,7 @@ mod tests {
28092812
None,
28102813
None,
28112814
None,
2815+
None,
28122816
false,
28132817
);
28142818
let nm = NodeManager::new(c, storage)

mutiny-core/src/notifications.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use crate::auth::MutinyAuthClient;
2+
use crate::{error::MutinyError, logging::MutinyLogger};
3+
use anyhow::anyhow;
4+
use lightning::util::logger::*;
5+
use lightning::{log_error, log_info};
6+
use reqwest::{Method, Url};
7+
use serde_json::{json, Value};
8+
use std::sync::Arc;
9+
10+
#[derive(Clone)]
11+
pub struct MutinyNotificationClient {
12+
auth_client: Option<Arc<MutinyAuthClient>>,
13+
client: Option<reqwest::Client>,
14+
url: String,
15+
id: Option<String>,
16+
pub logger: Arc<MutinyLogger>,
17+
}
18+
19+
impl MutinyNotificationClient {
20+
pub fn new_authenticated(
21+
auth_client: Arc<MutinyAuthClient>,
22+
url: String,
23+
logger: Arc<MutinyLogger>,
24+
) -> Self {
25+
log_info!(logger, "Creating authenticated notification client");
26+
Self {
27+
auth_client: Some(auth_client),
28+
client: None,
29+
url,
30+
id: None, // we get this from the auth client
31+
logger,
32+
}
33+
}
34+
35+
pub fn new_unauthenticated(
36+
url: String,
37+
identifier_key: String,
38+
logger: Arc<MutinyLogger>,
39+
) -> Self {
40+
log_info!(logger, "Creating unauthenticated notification client");
41+
Self {
42+
auth_client: None,
43+
client: Some(reqwest::Client::new()),
44+
url,
45+
id: Some(identifier_key),
46+
logger,
47+
}
48+
}
49+
50+
async fn make_request(
51+
&self,
52+
method: Method,
53+
url: Url,
54+
body: Option<Value>,
55+
) -> Result<reqwest::Response, MutinyError> {
56+
match (self.auth_client.as_ref(), self.client.as_ref()) {
57+
(Some(auth), _) => auth.request(method, url, body).await,
58+
(None, Some(client)) => {
59+
let mut request = client.request(method, url);
60+
if let Some(body) = body {
61+
request = request.json(&body);
62+
}
63+
request.send().await.map_err(|e| {
64+
log_error!(self.logger, "Error making request: {e}");
65+
MutinyError::Other(anyhow!("Error making request: {e}"))
66+
})
67+
}
68+
(None, None) => unreachable!("No auth client or http client"),
69+
}
70+
}
71+
72+
pub async fn register(&self, info: Value) -> Result<(), MutinyError> {
73+
let url = Url::parse(&format!("{}/register", self.url)).map_err(|e| {
74+
log_error!(self.logger, "Error parsing register url: {e}");
75+
MutinyError::InvalidArgumentsError
76+
})?;
77+
78+
let body = json!({"id": self.id, "info": info});
79+
80+
self.make_request(Method::POST, url, Some(body)).await?;
81+
82+
Ok(())
83+
}
84+
}

mutiny-wasm/src/lib.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use lnurl::lnurl::LnUrl;
3030
use mutiny_core::auth::MutinyAuthClient;
3131
use mutiny_core::lnurlauth::AuthManager;
3232
use mutiny_core::nostr::nwc::{BudgetedSpendingConditions, NwcProfileTag, SpendingConditions};
33+
use mutiny_core::notifications::MutinyNotificationClient;
3334
use mutiny_core::redshift::RedshiftManager;
3435
use mutiny_core::redshift::RedshiftRecipient;
3536
use mutiny_core::scb::EncryptedSCB;
@@ -80,6 +81,7 @@ impl MutinyWallet {
8081
subscription_url: Option<String>,
8182
storage_url: Option<String>,
8283
scorer_url: Option<String>,
84+
notification_url: Option<String>,
8385
do_not_connect_peers: Option<bool>,
8486
skip_device_lock: Option<bool>,
8587
safe_mode: Option<bool>,
@@ -174,6 +176,7 @@ impl MutinyWallet {
174176
auth_client,
175177
subscription_url,
176178
scorer_url,
179+
notification_url,
177180
skip_device_lock.unwrap_or(false),
178181
);
179182

@@ -1356,6 +1359,64 @@ impl MutinyWallet {
13561359
Ok(self.inner.reset_onchain_tracker().await?)
13571360
}
13581361

1362+
/// Register the wallet for web-push notifications
1363+
#[wasm_bindgen]
1364+
pub async fn register_web_push(&self, info: JsValue) -> Result<(), MutinyJsError> {
1365+
match self.inner.notification_client.as_ref() {
1366+
Some(client) => {
1367+
let info = info.into_serde()?;
1368+
client.register(info).await?;
1369+
}
1370+
None => return Err(MutinyJsError::NotFound),
1371+
}
1372+
1373+
Ok(())
1374+
}
1375+
1376+
/// test function for now, will delete in future
1377+
#[wasm_bindgen]
1378+
pub async fn test_register_web_push(
1379+
auth_url: String,
1380+
notification_url: String,
1381+
info: JsValue,
1382+
) -> Result<(), MutinyJsError> {
1383+
let logger = Arc::new(MutinyLogger::default());
1384+
let storage = IndexedDbStorage::new(None, None, None, logger.clone()).await?;
1385+
1386+
let mnemonic = storage.get_mnemonic()?.unwrap();
1387+
1388+
let seed = mnemonic.to_seed("");
1389+
let xprivkey = ExtendedPrivKey::new_master(Network::Signet, &seed).unwrap();
1390+
1391+
let auth_manager = AuthManager::new(xprivkey).unwrap();
1392+
1393+
let lnurl_client = Arc::new(
1394+
lnurl::Builder::default()
1395+
.build_async()
1396+
.expect("failed to make lnurl client"),
1397+
);
1398+
1399+
let auth_client = Arc::new(MutinyAuthClient::new(
1400+
auth_manager,
1401+
lnurl_client,
1402+
logger.clone(),
1403+
auth_url,
1404+
));
1405+
1406+
let notification_client = MutinyNotificationClient::new_authenticated(
1407+
auth_client,
1408+
notification_url,
1409+
logger.clone(),
1410+
);
1411+
1412+
let info = info.into_serde()?;
1413+
notification_client.register(info).await?;
1414+
1415+
log::info!("Registered!");
1416+
1417+
Ok(())
1418+
}
1419+
13591420
/// Exports the current state of the node manager to a json object.
13601421
#[wasm_bindgen]
13611422
pub async fn export_json(password: Option<String>) -> Result<String, MutinyJsError> {
@@ -1485,6 +1546,7 @@ mod tests {
14851546
None,
14861547
None,
14871548
None,
1549+
None,
14881550
)
14891551
.await
14901552
.expect("mutiny wallet should initialize");
@@ -1519,6 +1581,7 @@ mod tests {
15191581
None,
15201582
None,
15211583
None,
1584+
None,
15221585
)
15231586
.await
15241587
.unwrap();
@@ -1556,6 +1619,7 @@ mod tests {
15561619
None,
15571620
None,
15581621
None,
1622+
None,
15591623
)
15601624
.await
15611625
.expect("mutiny wallet should initialize");
@@ -1621,6 +1685,7 @@ mod tests {
16211685
None,
16221686
None,
16231687
None,
1688+
None,
16241689
)
16251690
.await
16261691
.expect("mutiny wallet should initialize");
@@ -1674,6 +1739,7 @@ mod tests {
16741739
None,
16751740
None,
16761741
None,
1742+
None,
16771743
)
16781744
.await
16791745
.expect("mutiny wallet should initialize");

0 commit comments

Comments
 (0)