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

Commit d99208d

Browse files
committed
Rework wasm apis for Contacts
1 parent eafa9ab commit d99208d

File tree

2 files changed

+90
-152
lines changed

2 files changed

+90
-152
lines changed

mutiny-wasm/src/lib.rs

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@ use futures::lock::Mutex;
2626
use gloo_utils::format::JsValueSerdeExt;
2727
use lightning::routing::gossip::NodeId;
2828
use lightning_invoice::Bolt11Invoice;
29+
use lnurl::lightning_address::LightningAddress;
2930
use lnurl::lnurl::LnUrl;
3031
use mutiny_core::auth::MutinyAuthClient;
3132
use mutiny_core::encrypt::encryption_key_from_pass;
33+
use mutiny_core::labels::Contact;
3234
use mutiny_core::lnurlauth::AuthManager;
3335
use mutiny_core::nostr::nip49::NIP49URI;
3436
use mutiny_core::nostr::nwc::{BudgetedSpendingConditions, NwcProfileTag, SpendingConditions};
3537
use mutiny_core::redshift::RedshiftManager;
3638
use mutiny_core::redshift::RedshiftRecipient;
3739
use mutiny_core::storage::{DeviceLock, MutinyStorage, DEVICE_LOCK_KEY};
38-
use mutiny_core::utils::sleep;
40+
use mutiny_core::utils::{now, sleep};
3941
use mutiny_core::vss::MutinyVssClient;
4042
use mutiny_core::{labels::LabelStorage, nodemanager::NodeManager};
4143
use mutiny_core::{logging::MutinyLogger, nostr::ProfileType};
@@ -1005,7 +1007,8 @@ impl MutinyWallet {
10051007
// find labels that have a contact and add them to the item
10061008
for label in a.labels.iter() {
10071009
if let Some(contact) = contacts.get(label) {
1008-
a.contacts.push(Contact::from(contact.clone()));
1010+
a.contacts
1011+
.push(TagItem::from((label.clone(), contact.clone())));
10091012
}
10101013
}
10111014
// remove labels that have a contact to prevent duplicates
@@ -1034,7 +1037,8 @@ impl MutinyWallet {
10341037
// find labels that have a contact and add them to the item
10351038
for a_label in a.labels.iter() {
10361039
if label == *a_label {
1037-
a.contacts.push(Contact::from(contact.clone()));
1040+
a.contacts
1041+
.push(TagItem::from((a_label.clone(), contact.clone())));
10381042
}
10391043
}
10401044
// remove labels that have the contact to prevent duplicates
@@ -1140,24 +1144,24 @@ impl MutinyWallet {
11401144
.set_invoice_labels(invoice, labels)?)
11411145
}
11421146

1143-
pub fn get_contacts(&self) -> Result<JsValue /* Map<String, Contact>*/, MutinyJsError> {
1147+
pub fn get_contacts(&self) -> Result<JsValue /* Map<String, TagItem>*/, MutinyJsError> {
11441148
Ok(JsValue::from_serde(
11451149
&self
11461150
.inner
11471151
.node_manager
11481152
.get_contacts()?
11491153
.into_iter()
1150-
.map(|(k, v)| (k, v.into()))
1151-
.collect::<HashMap<String, Contact>>(),
1154+
.map(|(k, v)| (k.clone(), (k, v).into()))
1155+
.collect::<HashMap<String, TagItem>>(),
11521156
)?)
11531157
}
11541158

1155-
pub fn get_contacts_sorted(&self) -> Result<JsValue /* Map<String, Contact>*/, MutinyJsError> {
1156-
let mut contacts: Vec<Contact> = self
1159+
pub fn get_contacts_sorted(&self) -> Result<JsValue /* Vec<TagItem>*/, MutinyJsError> {
1160+
let mut contacts: Vec<TagItem> = self
11571161
.inner
11581162
.node_manager
11591163
.get_contacts()?
1160-
.into_values()
1164+
.into_iter()
11611165
.map(|v| v.into())
11621166
.collect();
11631167

@@ -1174,36 +1178,88 @@ impl MutinyWallet {
11741178
.map(|c| (label, c).into()))
11751179
}
11761180

1177-
pub fn get_contact(&self, label: String) -> Result<Option<Contact>, MutinyJsError> {
1178-
Ok(self
1179-
.inner
1180-
.node_manager
1181-
.get_contact(label)?
1182-
.map(|c| c.into()))
1183-
}
1184-
11851181
/// Create a new contact from an existing label and returns the new identifying label
11861182
pub fn create_contact_from_label(
11871183
&self,
11881184
label: String,
1189-
contact: Contact,
1185+
name: String,
1186+
npub: Option<String>,
1187+
ln_address: Option<String>,
1188+
lnurl: Option<String>,
1189+
image_url: Option<String>,
11901190
) -> Result<String, MutinyJsError> {
1191+
let contact = Contact {
1192+
name,
1193+
npub: npub
1194+
.map(|n| bitcoin::XOnlyPublicKey::from_str(&n))
1195+
.transpose()?,
1196+
ln_address: ln_address
1197+
.map(|l| LightningAddress::from_str(&l))
1198+
.transpose()?,
1199+
lnurl: lnurl.map(|l| LnUrl::from_str(&l)).transpose()?,
1200+
image_url,
1201+
archived: None,
1202+
last_used: now().as_secs(),
1203+
};
1204+
11911205
Ok(self
11921206
.inner
11931207
.node_manager
1194-
.create_contact_from_label(label, contact.into())?)
1208+
.create_contact_from_label(label, contact)?)
11951209
}
11961210

1197-
pub fn create_new_contact(&self, contact: Contact) -> Result<String, MutinyJsError> {
1198-
Ok(self.inner.node_manager.create_new_contact(contact.into())?)
1211+
pub fn create_new_contact(
1212+
&self,
1213+
name: String,
1214+
npub: Option<String>,
1215+
ln_address: Option<String>,
1216+
lnurl: Option<String>,
1217+
image_url: Option<String>,
1218+
) -> Result<String, MutinyJsError> {
1219+
let contact = Contact {
1220+
name,
1221+
npub: npub
1222+
.map(|n| bitcoin::XOnlyPublicKey::from_str(&n))
1223+
.transpose()?,
1224+
ln_address: ln_address
1225+
.map(|l| LightningAddress::from_str(&l))
1226+
.transpose()?,
1227+
lnurl: lnurl.map(|l| LnUrl::from_str(&l)).transpose()?,
1228+
image_url,
1229+
archived: None,
1230+
last_used: now().as_secs(),
1231+
};
1232+
Ok(self.inner.node_manager.create_new_contact(contact)?)
11991233
}
12001234

12011235
pub fn archive_contact(&self, id: String) -> Result<(), MutinyJsError> {
12021236
Ok(self.inner.node_manager.archive_contact(id)?)
12031237
}
12041238

1205-
pub fn edit_contact(&self, id: String, contact: Contact) -> Result<(), MutinyJsError> {
1206-
Ok(self.inner.node_manager.edit_contact(id, contact.into())?)
1239+
pub fn edit_contact(
1240+
&self,
1241+
id: String,
1242+
name: String,
1243+
npub: Option<String>,
1244+
ln_address: Option<String>,
1245+
lnurl: Option<String>,
1246+
image_url: Option<String>,
1247+
) -> Result<(), MutinyJsError> {
1248+
let contact = Contact {
1249+
name,
1250+
npub: npub
1251+
.map(|n| bitcoin::XOnlyPublicKey::from_str(&n))
1252+
.transpose()?,
1253+
ln_address: ln_address
1254+
.map(|l| LightningAddress::from_str(&l))
1255+
.transpose()?,
1256+
lnurl: lnurl.map(|l| LnUrl::from_str(&l)).transpose()?,
1257+
image_url,
1258+
archived: None,
1259+
last_used: now().as_secs(),
1260+
};
1261+
1262+
Ok(self.inner.node_manager.edit_contact(id, contact)?)
12071263
}
12081264

12091265
pub fn get_tag_items(&self) -> Result<Vec<TagItem>, MutinyJsError> {

mutiny-wasm/src/models.rs

Lines changed: 11 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use crate::error::MutinyJsError;
21
use ::nostr::key::XOnlyPublicKey;
3-
use ::nostr::prelude::{FromBech32, ToBech32};
42
use bitcoin::hashes::hex::ToHex;
53
use bitcoin::secp256k1::PublicKey;
64
use bitcoin::{Address, OutPoint};
@@ -11,7 +9,6 @@ use lnurl::lnurl::LnUrl;
119
use mutiny_core::labels::Contact as MutinyContact;
1210
use mutiny_core::nostr::nwc::SpendingConditions;
1311
use mutiny_core::redshift::{RedshiftRecipient, RedshiftStatus};
14-
use mutiny_core::utils::now;
1512
use mutiny_core::*;
1613
use serde::{Deserialize, Serialize, Serializer};
1714
use serde_json::json;
@@ -35,7 +32,7 @@ pub struct ActivityItem {
3532
pub amount_sats: Option<u64>,
3633
pub inbound: bool,
3734
pub(crate) labels: Vec<String>,
38-
pub(crate) contacts: Vec<Contact>,
35+
pub(crate) contacts: Vec<TagItem>,
3936
pub last_updated: Option<u64>,
4037
}
4138

@@ -57,7 +54,7 @@ impl ActivityItem {
5754
}
5855

5956
#[wasm_bindgen(getter)]
60-
pub fn contacts(&self) -> Vec<Contact> {
57+
pub fn contacts(&self) -> Vec<TagItem> {
6158
self.contacts.clone()
6259
}
6360
}
@@ -698,6 +695,8 @@ pub struct TagItem {
698695
ln_address: Option<LightningAddress>,
699696
#[serde(skip_serializing_if = "Option::is_none")]
700697
lnurl: Option<LnUrl>,
698+
#[serde(skip_serializing_if = "Option::is_none")]
699+
image_url: Option<String>,
701700
/// Epoch time in seconds when this tag was last used
702701
pub last_used_time: u64,
703702
}
@@ -751,6 +750,11 @@ impl TagItem {
751750
pub fn lnurl(&self) -> Option<String> {
752751
self.lnurl.clone().map(|a| a.to_string())
753752
}
753+
754+
#[wasm_bindgen(getter)]
755+
pub fn image_url(&self) -> Option<String> {
756+
self.image_url.clone()
757+
}
754758
}
755759

756760
impl From<(String, MutinyContact)> for TagItem {
@@ -766,6 +770,7 @@ impl From<(String, MutinyContact)> for TagItem {
766770
npub,
767771
ln_address: contact.ln_address,
768772
lnurl: contact.lnurl,
773+
image_url: contact.image_url,
769774
last_used_time: contact.last_used,
770775
}
771776
}
@@ -781,137 +786,14 @@ impl From<labels::TagItem> for TagItem {
781786
npub: None,
782787
ln_address: None,
783788
lnurl: None,
789+
image_url: None,
784790
last_used_time: item.last_used_time,
785791
},
786792
labels::TagItem::Contact(contact) => contact.into(),
787793
}
788794
}
789795
}
790796

791-
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
792-
#[wasm_bindgen]
793-
pub struct Contact {
794-
name: String,
795-
#[serde(skip_serializing_if = "Option::is_none")]
796-
npub: Option<String>,
797-
#[serde(skip_serializing_if = "Option::is_none")]
798-
ln_address: Option<LightningAddress>,
799-
#[serde(skip_serializing_if = "Option::is_none")]
800-
lnurl: Option<LnUrl>,
801-
#[serde(skip_serializing_if = "Option::is_none")]
802-
image_url: Option<String>,
803-
pub last_used: u64,
804-
}
805-
806-
impl PartialOrd for Contact {
807-
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
808-
Some(self.cmp(other))
809-
}
810-
}
811-
812-
impl Ord for Contact {
813-
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
814-
// sort last used time in descending order
815-
// then sort by name
816-
other
817-
.last_used
818-
.cmp(&self.last_used)
819-
.then(self.name.cmp(&other.name))
820-
}
821-
}
822-
823-
#[wasm_bindgen]
824-
impl Contact {
825-
#[wasm_bindgen(constructor)]
826-
pub fn new(
827-
name: String,
828-
npub: Option<String>,
829-
ln_address: Option<String>,
830-
lnurl: Option<String>,
831-
image_url: Option<String>,
832-
) -> Result<Contact, MutinyJsError> {
833-
// Convert the parameters into the types expected by the struct
834-
let ln_address = ln_address
835-
.map(|s| LightningAddress::from_str(&s))
836-
.transpose()?;
837-
let lnurl = lnurl.map(|s| LnUrl::from_str(&s)).transpose()?;
838-
839-
Ok(Contact {
840-
name,
841-
npub,
842-
ln_address,
843-
lnurl,
844-
image_url,
845-
last_used: now().as_secs(),
846-
})
847-
}
848-
849-
#[wasm_bindgen(getter)]
850-
pub fn value(&self) -> JsValue {
851-
JsValue::from_serde(&serde_json::to_value(self).unwrap()).unwrap()
852-
}
853-
854-
#[wasm_bindgen(getter)]
855-
pub fn name(&self) -> String {
856-
self.name.clone()
857-
}
858-
859-
#[wasm_bindgen(getter)]
860-
pub fn npub(&self) -> Option<String> {
861-
self.npub.clone()
862-
}
863-
864-
#[wasm_bindgen(getter)]
865-
pub fn ln_address(&self) -> Option<String> {
866-
self.ln_address.clone().map(|a| a.to_string())
867-
}
868-
869-
#[wasm_bindgen(getter)]
870-
pub fn lnurl(&self) -> Option<String> {
871-
self.lnurl.clone().map(|a| a.to_string())
872-
}
873-
874-
#[wasm_bindgen(getter)]
875-
pub fn image_url(&self) -> Option<String> {
876-
self.image_url.clone().map(|a| a.to_string())
877-
}
878-
}
879-
880-
impl From<Contact> for MutinyContact {
881-
fn from(c: Contact) -> Self {
882-
let npub = c.npub.and_then(|n| XOnlyPublicKey::from_bech32(n).ok());
883-
let npub = npub.map(|a| bitcoin::XOnlyPublicKey::from_slice(&a.serialize()).unwrap());
884-
MutinyContact {
885-
name: c.name,
886-
npub,
887-
ln_address: c.ln_address,
888-
lnurl: c.lnurl,
889-
archived: Some(false),
890-
image_url: c.image_url,
891-
last_used: c.last_used,
892-
}
893-
}
894-
}
895-
896-
impl From<MutinyContact> for Contact {
897-
fn from(c: MutinyContact) -> Self {
898-
let npub = c.npub.and_then(|a| {
899-
XOnlyPublicKey::from_slice(&a.serialize())
900-
.unwrap()
901-
.to_bech32()
902-
.ok()
903-
});
904-
Contact {
905-
name: c.name,
906-
npub,
907-
ln_address: c.ln_address,
908-
lnurl: c.lnurl,
909-
image_url: c.image_url,
910-
last_used: c.last_used,
911-
}
912-
}
913-
}
914-
915797
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
916798
#[wasm_bindgen]
917799
pub struct NwcProfile {

0 commit comments

Comments
 (0)