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

Commit a8b07f5

Browse files
committed
Upload profile pic to nostr.build
1 parent 9110d3f commit a8b07f5

File tree

6 files changed

+79
-1
lines changed

6 files changed

+79
-1
lines changed

Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mutiny-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ lightning-transaction-sync = { version = "0.0.118", features = ["esplora-async-h
3535
lightning-liquidity = { git = "https://github.com/johncantrell97/ldk-lsp-client.git", rev = "9e01757d20c04aa31c28de8c4ffab5442d547edc" }
3636
chrono = "0.4.22"
3737
futures-util = { version = "0.3", default-features = false }
38-
reqwest = { version = "0.11", default-features = false, features = ["json"] }
38+
reqwest = { version = "0.11", default-features = false, features = ["multipart", "json"] }
3939
async-trait = "0.1.68"
4040
url = { version = "2.3.1", features = ["serde"] }
4141
nostr = { version = "0.27.0", default-features = false, features = ["nip04", "nip05", "nip47", "nip57"] }

mutiny-core/src/lib.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ use lightning::{log_error, log_info, log_warn};
8787
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription};
8888
use lnurl::{lnurl::LnUrl, AsyncClient as LnUrlClient, LnUrlResponse, Response};
8989
use nostr_sdk::{Client, RelayPoolNotification};
90+
use reqwest::multipart::{Form, Part};
9091
use serde::{Deserialize, Serialize};
9192
use serde_json::{json, Value};
9293
use std::sync::Arc;
@@ -1384,6 +1385,42 @@ impl<S: MutinyStorage> MutinyWallet<S> {
13841385
Ok(())
13851386
}
13861387

1388+
/// Uploads a profile pic to nostr.build and returns the uploaded file's URL
1389+
pub async fn upload_profile_pic(&self, image_bytes: Vec<u8>) -> Result<String, MutinyError> {
1390+
let client = reqwest::Client::new();
1391+
1392+
let form = Form::new().part("fileToUpload", Part::bytes(image_bytes));
1393+
let res: NostrBuildResult = client
1394+
.post("https://nostr.build/api/v2/upload/profile")
1395+
.multipart(form)
1396+
.send()
1397+
.await
1398+
.map_err(|_| MutinyError::NostrError)?
1399+
.json()
1400+
.await
1401+
.map_err(|_| MutinyError::NostrError)?;
1402+
1403+
if res.status != "success" {
1404+
log_error!(
1405+
self.logger,
1406+
"Error uploading profile picture: {}",
1407+
res.message
1408+
);
1409+
return Err(MutinyError::NostrError);
1410+
}
1411+
1412+
// get url from response body
1413+
if let Some(value) = res.data.first() {
1414+
return value
1415+
.get("url")
1416+
.and_then(|v| v.as_str())
1417+
.map(|s| s.to_string())
1418+
.ok_or(MutinyError::NostrError);
1419+
}
1420+
1421+
Err(MutinyError::NostrError)
1422+
}
1423+
13871424
/// Makes a request to the primal api
13881425
async fn primal_request(
13891426
client: &reqwest::Client,
@@ -2106,6 +2143,13 @@ pub(crate) async fn create_new_federation<S: MutinyStorage>(
21062143
})
21072144
}
21082145

2146+
#[derive(Deserialize)]
2147+
struct NostrBuildResult {
2148+
status: String,
2149+
message: String,
2150+
data: Vec<Value>,
2151+
}
2152+
21092153
#[cfg(test)]
21102154
mod tests {
21112155
use crate::{

mutiny-wasm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ urlencoding = "2.1.2"
4343
once_cell = "1.18.0"
4444
payjoin = { version = "0.13.0", features = ["send", "base64"] }
4545
fedimint-core = "0.2.1"
46+
base64 = "0.13.0"
4647

4748
# The `console_error_panic_hook` crate provides better debugging of panics by
4849
# logging them with `console.error`. This is great for development, but requires

mutiny-wasm/src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ impl From<MutinyStorageError> for MutinyJsError {
232232
}
233233
}
234234

235+
impl From<base64::DecodeError> for MutinyJsError {
236+
fn from(_e: base64::DecodeError) -> Self {
237+
Self::InvalidArgumentsError
238+
}
239+
}
240+
235241
impl From<bip39::Error> for MutinyJsError {
236242
fn from(_e: bip39::Error) -> Self {
237243
Self::InvalidMnemonic

mutiny-wasm/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,12 @@ impl MutinyWallet {
16741674
Ok(event_id.to_hex())
16751675
}
16761676

1677+
/// Uploads a profile pic to nostr.build and returns the uploaded file's URL
1678+
pub async fn upload_profile_pic(&self, img_base64: String) -> Result<String, MutinyJsError> {
1679+
let bytes = base64::decode(&img_base64)?;
1680+
Ok(self.inner.upload_profile_pic(bytes).await?)
1681+
}
1682+
16771683
/// Resets the scorer and network graph. This can be useful if you get stuck in a bad state.
16781684
#[wasm_bindgen]
16791685
pub async fn reset_router(&self) -> Result<(), MutinyJsError> {

0 commit comments

Comments
 (0)