From afeb226e4ff093239995c7799c1795f1a07015f9 Mon Sep 17 00:00:00 2001 From: pythcoiner Date: Thu, 27 Feb 2025 18:14:27 +0100 Subject: [PATCH] project: add qt_joinstr crate => C++/Qt bindings --- .gitignore | 1 + Cargo.toml | 10 +++- justfile | 5 ++ rust/joinstr/src/interface.rs | 1 + rust/qt_joinstr/Cargo.toml | 16 ++++++ rust/qt_joinstr/build.rs | 5 ++ rust/qt_joinstr/build.sh | 3 + rust/qt_joinstr/src/lib.rs | 102 ++++++++++++++++++++++++++++++++++ 8 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 rust/qt_joinstr/Cargo.toml create mode 100644 rust/qt_joinstr/build.rs create mode 100755 rust/qt_joinstr/build.sh create mode 100644 rust/qt_joinstr/src/lib.rs diff --git a/.gitignore b/.gitignore index 807db7c..a1f95dc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ /dart/lib/ /rust/joinstr/include /rust/joinstr_wallet/include +/rust/qt_joinstr/include Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 5fc9622..50e5035 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ "rust/joinstr", "rust/simple_nostr_client", "rust/simple_electrum_client", - "rust/joinstr_wallet", + "rust/joinstr_wallet", "rust/qt_joinstr", ] [workspace.dependencies] @@ -33,3 +33,11 @@ simple_nostr_client = { path = "rust/simple_nostr_client" } tokio = "1.40.0" url = "2.5.4" websocket = { version = "0.27.1", default-features = false } + +cxx = "1.0.141" +cxx-qt = "0.7.0" +cxx-qt-lib = "0.7.0" +# cxx-qt = { path = "../cxx-qt/crates/cxx-qt" } +# cxx-qt-lib = { path = "../cxx-qt/crates/cxx-qt-lib" } +cxx-qt-build = "0.7.0" +# cxx-qt-build = { path = "../cxx-qt/crates/cxx-qt-build", features = ["link_qt_object_files"] } diff --git a/justfile b/justfile index 6a0c2a9..ad1ef91 100644 --- a/justfile +++ b/justfile @@ -5,6 +5,7 @@ clean: rm -fRd target rm -fRd rust/joinstr/include/* rm -fRd rust/joinstr_wallet/include/* + rm -fRd rust/qt_joinstr/include/* rm -fRd dart/lib/joinstr.dart rm -fRd dart/android rm -fRd dart/ios @@ -26,3 +27,7 @@ wallet: cp target/release/libjoinstr_wallet.a rust/joinstr_wallet/include/libjoinstr_wallet.a cp target/release/libjoinstr_wallet.d rust/joinstr_wallet/include/libjoinstr_wallet.d cp target/release/libjoinstr_wallet.so rust/joinstr_wallet/include/libjoinstr_wallet.so + +qt: + just clean + ./rust/qt_joinstr/build.sh diff --git a/rust/joinstr/src/interface.rs b/rust/joinstr/src/interface.rs index f8d4b04..6a69b45 100644 --- a/rust/joinstr/src/interface.rs +++ b/rust/joinstr/src/interface.rs @@ -11,6 +11,7 @@ use crate::{ utils::now, }; +#[derive(Debug)] pub enum Error { Unknown, NostrClient(crate::nostr::error::Error), diff --git a/rust/qt_joinstr/Cargo.toml b/rust/qt_joinstr/Cargo.toml new file mode 100644 index 0000000..871d73d --- /dev/null +++ b/rust/qt_joinstr/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "qt_joinstr" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["rlib", "cdylib", "staticlib"] + +[dependencies] +joinstr.workspace = true +cxx.workspace = true +cxx-qt.workspace = true +cxx-qt-lib.workspace = true + +[build-dependencies] +cxx-qt-build = { workspace = true, features = ["link_qt_object_files"] } diff --git a/rust/qt_joinstr/build.rs b/rust/qt_joinstr/build.rs new file mode 100644 index 0000000..88a7fbc --- /dev/null +++ b/rust/qt_joinstr/build.rs @@ -0,0 +1,5 @@ +use cxx_qt_build::CxxQtBuilder; + +fn main() { + CxxQtBuilder::new().file("src/lib.rs").build(); +} diff --git a/rust/qt_joinstr/build.sh b/rust/qt_joinstr/build.sh new file mode 100755 index 0000000..d29dfaf --- /dev/null +++ b/rust/qt_joinstr/build.sh @@ -0,0 +1,3 @@ +export CXX_QT_EXPORT_CRATE_qt_joinstr=1 +export CXX_QT_EXPORT_DIR="./include" +cargo build -p qt_joinstr --release diff --git a/rust/qt_joinstr/src/lib.rs b/rust/qt_joinstr/src/lib.rs new file mode 100644 index 0000000..95d6505 --- /dev/null +++ b/rust/qt_joinstr/src/lib.rs @@ -0,0 +1,102 @@ +use cpp_joinstr::{Coin, ListCoinsResult, Network, QString, QUrl}; +use joinstr::{interface, miniscript::bitcoin}; + +#[cxx_qt::bridge] +pub mod cpp_joinstr { + + unsafe extern "C++" { + include!("cxx-qt-lib/qstring.h"); + type QString = cxx_qt_lib::QString; + + include!("cxx-qt-lib/qurl.h"); + type QUrl = cxx_qt_lib::QUrl; + } + + extern "Rust" { + + fn list_coins( + mnemonics: QString, + electrum_address: QUrl, + start_index: u32, + stop_index: u32, + network: Network, + ) -> ListCoinsResult; + } + + struct Coin { + outpoint: QString, + value: u64, + } + + struct ListCoinsResult { + coins: Vec, + error: String, + } + + enum Network { + /// Mainnet Bitcoin. + Bitcoin, + /// Bitcoin's testnet network. + Testnet, + /// Bitcoin's signet network. + Signet, + /// Bitcoin's regtest network. + Regtest, + } +} + +impl From for bitcoin::Network { + fn from(value: Network) -> Self { + match value { + Network::Bitcoin => Self::Bitcoin, + Network::Testnet => Self::Testnet, + Network::Signet => Self::Signet, + Network::Regtest => Self::Regtest, + _ => unreachable!(), + } + } +} + +fn list_coins( + mnemonics: QString, + electrum_address: QUrl, + start_index: u32, + stop_index: u32, + network: Network, +) -> ListCoinsResult { + let electrum_port = electrum_address.port_or(-1); + if electrum_port == -1 { + return ListCoinsResult { + coins: Vec::new(), + error: "electrum_address.port must be specified!".to_string(), + }; + } + + let res = interface::list_coins( + mnemonics.to_string(), + electrum_address.to_string(), + electrum_port as u16, + (start_index, stop_index), + network.into(), + ); + + let mut result = ListCoinsResult { + coins: Vec::new(), + error: String::new(), + }; + + match res { + Ok(r) => { + result.coins = r + .into_iter() + .map(|c| Coin { + outpoint: c.outpoint.to_string().into(), + value: c.txout.value.to_sat(), + }) + .collect() + } + Err(e) => result.error = format!("{:?}", e), + } + + result +}