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

Commit 9081d44

Browse files
committed
WIP: Notification client
1 parent 10eb4ed commit 9081d44

File tree

4 files changed

+154
-0
lines changed

4 files changed

+154
-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;
@@ -54,13 +55,16 @@ use crate::labels::{Contact, LabelStorage};
5455
use crate::nostr::nwc::{
5556
BudgetPeriod, BudgetedSpendingConditions, NwcProfileTag, SpendingConditions,
5657
};
58+
use crate::notifications::MutinyNotificationClient;
5759
use crate::storage::{MutinyStorage, DEVICE_ID_KEY, EXPECTED_NETWORK_KEY, NEED_FULL_SYNC_KEY};
5860
use crate::{error::MutinyError, nostr::ReservedProfile};
5961
use crate::{nodemanager::NodeManager, nostr::ProfileType};
6062
use crate::{nostr::NostrManager, utils::sleep};
6163
use ::nostr::key::XOnlyPublicKey;
6264
use ::nostr::{Event, Kind, Metadata};
6365
use bip39::Mnemonic;
66+
use bitcoin::hashes::hex::ToHex;
67+
use bitcoin::hashes::{sha256, Hash};
6468
use bitcoin::secp256k1::PublicKey;
6569
use bitcoin::util::bip32::ExtendedPrivKey;
6670
use bitcoin::Network;
@@ -86,6 +90,7 @@ pub struct MutinyWalletConfig {
8690
auth_client: Option<Arc<MutinyAuthClient>>,
8791
subscription_url: Option<String>,
8892
scorer_url: Option<String>,
93+
notification_url: Option<String>,
8994
do_not_connect_peers: bool,
9095
skip_device_lock: bool,
9196
pub safe_mode: bool,
@@ -103,6 +108,7 @@ impl MutinyWalletConfig {
103108
auth_client: Option<Arc<MutinyAuthClient>>,
104109
subscription_url: Option<String>,
105110
scorer_url: Option<String>,
111+
notification_url: Option<String>,
106112
skip_device_lock: bool,
107113
) -> Self {
108114
Self {
@@ -113,6 +119,7 @@ impl MutinyWalletConfig {
113119
user_esplora_url,
114120
user_rgs_url,
115121
scorer_url,
122+
notification_url,
116123
lsp_url,
117124
auth_client,
118125
subscription_url,
@@ -142,6 +149,7 @@ pub struct MutinyWallet<S: MutinyStorage> {
142149
pub storage: S,
143150
pub node_manager: Arc<NodeManager<S>>,
144151
pub nostr: Arc<NostrManager<S>>,
152+
pub notification_client: Option<Arc<MutinyNotificationClient>>,
145153
}
146154

147155
impl<S: MutinyStorage> MutinyWallet<S> {
@@ -163,6 +171,31 @@ impl<S: MutinyStorage> MutinyWallet<S> {
163171

164172
NodeManager::start_sync(node_manager.clone());
165173

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

180214
#[cfg(not(test))]
@@ -632,6 +666,7 @@ mod tests {
632666
None,
633667
None,
634668
None,
669+
None,
635670
false,
636671
);
637672
let mw = MutinyWallet::new(storage.clone(), config)
@@ -662,6 +697,7 @@ mod tests {
662697
None,
663698
None,
664699
None,
700+
None,
665701
false,
666702
);
667703
let mut mw = MutinyWallet::new(storage.clone(), config)
@@ -698,6 +734,7 @@ mod tests {
698734
None,
699735
None,
700736
None,
737+
None,
701738
false,
702739
);
703740
let mut mw = MutinyWallet::new(storage.clone(), config)
@@ -735,6 +772,7 @@ mod tests {
735772
None,
736773
None,
737774
None,
775+
None,
738776
false,
739777
);
740778
let mw = MutinyWallet::new(storage.clone(), config)
@@ -760,6 +798,7 @@ mod tests {
760798
None,
761799
None,
762800
None,
801+
None,
763802
false,
764803
);
765804
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: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ impl MutinyWallet {
9090
subscription_url: Option<String>,
9191
storage_url: Option<String>,
9292
scorer_url: Option<String>,
93+
notification_url: Option<String>,
9394
do_not_connect_peers: Option<bool>,
9495
skip_device_lock: Option<bool>,
9596
safe_mode: Option<bool>,
@@ -114,6 +115,7 @@ impl MutinyWallet {
114115
subscription_url,
115116
storage_url,
116117
scorer_url,
118+
notification_url,
117119
do_not_connect_peers,
118120
skip_device_lock,
119121
safe_mode,
@@ -142,6 +144,7 @@ impl MutinyWallet {
142144
subscription_url: Option<String>,
143145
storage_url: Option<String>,
144146
scorer_url: Option<String>,
147+
notification_url: Option<String>,
145148
do_not_connect_peers: Option<bool>,
146149
skip_device_lock: Option<bool>,
147150
safe_mode: Option<bool>,
@@ -235,6 +238,7 @@ impl MutinyWallet {
235238
auth_client,
236239
subscription_url,
237240
scorer_url,
241+
notification_url,
238242
skip_device_lock.unwrap_or(false),
239243
);
240244

@@ -1431,6 +1435,22 @@ impl MutinyWallet {
14311435
Ok(self.inner.reset_onchain_tracker().await?)
14321436
}
14331437

1438+
/// Register the wallet for web-push notifications
1439+
#[wasm_bindgen]
1440+
pub async fn register_web_push(&self, info: JsValue) -> Result<(), MutinyJsError> {
1441+
match self.inner.notification_client.as_ref() {
1442+
Some(client) => {
1443+
let info = info.into_serde()?;
1444+
client.register(info).await?;
1445+
}
1446+
None => return Err(MutinyJsError::NotFound),
1447+
}
1448+
1449+
log::info!("Web Push Registered!");
1450+
1451+
Ok(())
1452+
}
1453+
14341454
/// Exports the current state of the node manager to a json object.
14351455
#[wasm_bindgen]
14361456
pub async fn export_json(password: Option<String>) -> Result<String, MutinyJsError> {
@@ -1561,6 +1581,7 @@ mod tests {
15611581
None,
15621582
None,
15631583
None,
1584+
None,
15641585
)
15651586
.await
15661587
.expect("mutiny wallet should initialize");
@@ -1594,6 +1615,7 @@ mod tests {
15941615
None,
15951616
None,
15961617
None,
1618+
None,
15971619
)
15981620
.await
15991621
.expect("mutiny wallet should initialize");
@@ -1616,6 +1638,7 @@ mod tests {
16161638
None,
16171639
None,
16181640
None,
1641+
None,
16191642
)
16201643
.await;
16211644

@@ -1654,6 +1677,7 @@ mod tests {
16541677
None,
16551678
None,
16561679
None,
1680+
None,
16571681
)
16581682
.await
16591683
.unwrap();
@@ -1692,6 +1716,7 @@ mod tests {
16921716
None,
16931717
None,
16941718
None,
1719+
None,
16951720
)
16961721
.await
16971722
.expect("mutiny wallet should initialize");
@@ -1758,6 +1783,7 @@ mod tests {
17581783
None,
17591784
None,
17601785
None,
1786+
None,
17611787
)
17621788
.await
17631789
.expect("mutiny wallet should initialize");
@@ -1812,6 +1838,7 @@ mod tests {
18121838
None,
18131839
None,
18141840
None,
1841+
None,
18151842
)
18161843
.await
18171844
.expect("mutiny wallet should initialize");

0 commit comments

Comments
 (0)