Skip to content

Commit

Permalink
Add WebLN::get_info
Browse files Browse the repository at this point in the history
  • Loading branch information
yukibtc committed Jan 19, 2024
1 parent ea7c8fb commit 538c935
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 5 deletions.
35 changes: 35 additions & 0 deletions webln-js/src/get_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2024 Yuki Kishimoto
// Distributed under the MIT software license

use wasm_bindgen::prelude::*;
use webln::GetInfoResponse;

#[wasm_bindgen(js_name = GetInfoResponse)]
pub struct JsGetInfoResponse {
inner: GetInfoResponse,
}

impl From<GetInfoResponse> for JsGetInfoResponse {
fn from(inner: GetInfoResponse) -> Self {
Self { inner }
}
}

#[wasm_bindgen(js_class = GetInfoResponse)]
impl JsGetInfoResponse {
pub fn alias(&self) -> Option<String> {
self.inner.node.alias.clone()
}

pub fn pubkey(&self) -> Option<String> {
self.inner.node.pubkey.clone()
}

pub fn color(&self) -> Option<String> {
self.inner.node.color.clone()
}

pub fn methods(&self) -> Vec<String> {
self.inner.methods.iter().map(|m| m.to_string()).collect()
}
}
8 changes: 8 additions & 0 deletions webln-js/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
#![allow(non_snake_case)]
#![allow(clippy::new_without_default)]

use get_info::JsGetInfoResponse;
use wasm_bindgen::prelude::*;
use webln::WebLN;

pub mod error;
pub mod get_info;

use self::error::{into_err, Result};

Expand Down Expand Up @@ -46,4 +48,10 @@ impl JsWebLN {
pub async fn enable(&self) -> Result<()> {
self.inner.enable().await.map_err(into_err)
}

/// Get information about the connected node and what WebLN methods it supports.
#[wasm_bindgen(js_name = getInfo)]
pub async fn get_info(&self) -> Result<JsGetInfoResponse> {
Ok(self.inner.get_info().await.map_err(into_err)?.into())
}
}
123 changes: 118 additions & 5 deletions webln/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@

use core::fmt;

use js_sys::{Function, Object, Promise, Reflect};
use js_sys::{Array, Function, Object, Promise, Reflect};
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::JsFuture;
use web_sys::Window;

pub const IS_ENABLED: &str = "isEnabled";
pub const ENABLE: &str = "enable";
pub const GET_INFO: &str = "getInfo";

/// WebLN error
#[derive(Debug)]
pub enum Error {
Expand Down Expand Up @@ -45,6 +49,85 @@ impl From<JsValue> for Error {
}
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetInfoNode {
pub alias: Option<String>,
pub pubkey: Option<String>,
pub color: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum GetInfoMethod {
IsEnabled,
Enable,
GetInfo,
Keysend,
MakeInvoice,
SendPayment,
SendPaymentAsync,
SignMessage,
VerifyMessage,
Request,
Lnurl,
On,
Off,
GetBalance,
Other(String),
}

impl<S> From<S> for GetInfoMethod
where
S: AsRef<str>,
{
fn from(method: S) -> Self {
match method.as_ref() {
IS_ENABLED => Self::IsEnabled,
ENABLE => Self::Enable,
GET_INFO => Self::GetInfo,
"keysend" => Self::Keysend,
"makeInvoice" => Self::MakeInvoice,
"sendPayment" => Self::SendPayment,
"sendPaymentAsync" => Self::SendPaymentAsync,
"signMessage" => Self::SignMessage,
"verifyMessage" => Self::VerifyMessage,
"request" => Self::Request,
"lnurl" => Self::Lnurl,
"on" => Self::On,
"off" => Self::Off,
"getBalance" => Self::GetBalance,
other => Self::Other(other.to_string()),
}
}
}

impl fmt::Display for GetInfoMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::IsEnabled => write!(f, "{IS_ENABLED}"),
Self::Enable => write!(f, "{ENABLE}"),
Self::GetInfo => write!(f, "{GET_INFO}"),
Self::Keysend => write!(f, "keysend"),
Self::MakeInvoice => write!(f, "makeInvoice"),
Self::SendPayment => write!(f, "sendPayment"),
Self::SendPaymentAsync => write!(f, "sendPaymentAsync"),
Self::SignMessage => write!(f, "signMessage"),
Self::VerifyMessage => write!(f, "verifyMessage"),
Self::Request => write!(f, "request"),
Self::Lnurl => write!(f, "lnurl"),
Self::On => write!(f, "on"),
Self::Off => write!(f, "off"),
Self::GetBalance => write!(f, "getBalance"),
Self::Other(other) => write!(f, "{other}"),
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetInfoResponse {
pub node: GetInfoNode,
pub methods: Vec<GetInfoMethod>,
}

/// WebLN instance
#[derive(Debug, Clone)]
pub struct WebLN {
Expand Down Expand Up @@ -75,16 +158,16 @@ impl WebLN {
.map_err(|_| Error::NamespaceNotFound(name.to_string()))
}

/* /// Get value from object key
/// Get value from object key
fn get_value_by_key(&self, obj: &Object, key: &str) -> Result<JsValue, Error> {
Reflect::get(obj, &JsValue::from_str(key))
.map_err(|_| Error::ObjectKeyNotFound(key.to_string()))
} */
}

/// Check if `webln` is enabled without explicitly enabling it through `webln.enable()`
/// (which may cause a confirmation popup in some providers)
pub async fn is_enabled(&self) -> Result<bool, Error> {
let func: Function = self.get_func(&self.webln_obj, "isEnabled")?;
let func: Function = self.get_func(&self.webln_obj, IS_ENABLED)?;
let promise: Promise = Promise::resolve(&func.call0(&self.webln_obj)?);
let result: JsValue = JsFuture::from(promise).await?;
result
Expand All @@ -96,9 +179,39 @@ impl WebLN {
/// Calling `webln.enable()` will prompt the user for permission to use the WebLN capabilities of the browser.
/// After that you are free to call any of the other API methods.
pub async fn enable(&self) -> Result<(), Error> {
let func: Function = self.get_func(&self.webln_obj, "enable")?;
let func: Function = self.get_func(&self.webln_obj, ENABLE)?;
let promise: Promise = Promise::resolve(&func.call0(&self.webln_obj)?);
JsFuture::from(promise).await?;
Ok(())
}

/// Get information about the connected node and what WebLN methods it supports.
pub async fn get_info(&self) -> Result<GetInfoResponse, Error> {
let func: Function = self.get_func(&self.webln_obj, GET_INFO)?;
let promise: Promise = Promise::resolve(&func.call0(&self.webln_obj)?);
let result: JsValue = JsFuture::from(promise).await?;
let get_info_obj: Object = result.dyn_into()?;

let node_obj: Object = self.get_value_by_key(&get_info_obj, "node")?.dyn_into()?;

// Extract data
let alias: Option<String> = self.get_value_by_key(&node_obj, "alias")?.as_string();
let pubkey: Option<String> = self.get_value_by_key(&node_obj, "pubkey")?.as_string();
let color: Option<String> = self.get_value_by_key(&node_obj, "color")?.as_string();
let methods_array: Array = self.get_value_by_key(&get_info_obj, "methods")?.into();
let methods: Vec<GetInfoMethod> = methods_array
.into_iter()
.filter_map(|m| m.as_string())
.map(GetInfoMethod::from)
.collect();

Ok(GetInfoResponse {
node: GetInfoNode {
alias,
pubkey,
color,
},
methods,
})
}
}

0 comments on commit 538c935

Please sign in to comment.