Skip to content

Commit 67e887f

Browse files
committed
f Allow node runner to accepts HTTP request on /payjoin endpoint
1 parent 65b23e6 commit 67e887f

File tree

6 files changed

+144
-255
lines changed

6 files changed

+144
-255
lines changed

Cargo.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,14 @@ tokio = { version = "1", default-features = false, features = [ "rt-multi-thread
6969
esplora-client = { version = "0.6", default-features = false }
7070
libc = "0.2"
7171
uniffi = { version = "0.26.0", features = ["build"], optional = true }
72-
axum = "0.7.4"
7372
payjoin = { version = "0.13.0", features = ["receive", "send"] }
7473
http-body-util = "0.1.0"
7574
bitcoincore-rpc = "0.17.0"
75+
ureq = "2.9.1"
76+
hyper = {version = "1.2.0", features = ["http1", "server"]}
77+
rustls = "0.21.9"
78+
bytes = "1.5.0"
79+
hyper-util = {version = "0.1.3", features = ["tokio"] }
7680

7781
[target.'cfg(vss)'.dependencies]
7882
vss-client = "0.2"

src/lib.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ pub mod io;
8585
mod liquidity;
8686
mod logger;
8787
mod message_handler;
88-
mod payjoin;
8988
mod payment_store;
9089
mod peer_store;
90+
mod pj;
9191
mod sweep;
9292
mod tx_broadcaster;
9393
mod types;
@@ -583,6 +583,10 @@ impl<K: KVStore + Sync + Send + 'static> Node<K> {
583583
});
584584
}
585585

586+
runtime.spawn(async move {
587+
pj::Receiver::start().await.unwrap();
588+
});
589+
586590
// Regularly reconnect to channel peers.
587591
let connect_cm = Arc::clone(&self.channel_manager);
588592
let connect_pm = Arc::clone(&self.peer_manager);
@@ -800,7 +804,7 @@ impl<K: KVStore + Sync + Send + 'static> Node<K> {
800804
pub fn payjoin_uri(&self) -> Result<String, Error> {
801805
let address = self.wallet.get_new_address()?;
802806
let amount = Amount::from_sat(1000);
803-
let pj = "https://localhost:3227/payjoin";
807+
let pj = "https://0.0.0.0:3227/payjoin";
804808
let pj_uri_string = format!("{}?amount={}&pj={}", address.to_qr_uri(), amount.to_btc(), pj);
805809
assert!(Uri::from_str(&pj_uri_string).is_ok());
806810
Ok(pj_uri_string)

src/payjoin.rs

-197
This file was deleted.

src/pj.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use bitcoin::address::NetworkChecked;
2+
use hyper::HeaderMap;
3+
use payjoin::bitcoin::{self, Amount};
4+
use payjoin::Uri;
5+
use std::str::FromStr;
6+
7+
struct Headers(HeaderMap);
8+
9+
impl payjoin::receive::Headers for Headers {
10+
fn get_header(&self, key: &str) -> Option<&str> {
11+
self.0.get(key).and_then(|v| v.to_str().ok())
12+
}
13+
}
14+
15+
pub struct Receiver;
16+
17+
impl Receiver {
18+
pub async fn start() -> Result<(), Box<dyn std::error::Error>> {
19+
http_server::start().await.unwrap();
20+
Ok(())
21+
}
22+
23+
fn _build_pj_uri(
24+
address: bitcoin::Address, amount: Amount, pj: &'static str,
25+
) -> Result<Uri<'static, NetworkChecked>, Box<dyn std::error::Error>> {
26+
let pj_uri_string = format!("{}?amount={}&pj={}", address.to_qr_uri(), amount.to_btc(), pj);
27+
let pj_uri = Uri::from_str(&pj_uri_string).map_err(|e| e.to_string())?;
28+
Ok(pj_uri.assume_checked())
29+
}
30+
}
31+
32+
mod http_server {
33+
use bytes::Bytes;
34+
use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};
35+
use hyper::server::conn::http1;
36+
use hyper::service::service_fn;
37+
use hyper::{Method, Request, Response, StatusCode};
38+
use hyper_util::rt::TokioIo;
39+
use std::net::SocketAddr;
40+
use tokio::net::TcpListener;
41+
42+
pub async fn start() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
43+
let addr = SocketAddr::from(([127, 0, 0, 1], 3227));
44+
let listener = TcpListener::bind(addr).await?;
45+
println!("Listening on http://{}", addr);
46+
loop {
47+
let (stream, _) = listener.accept().await?;
48+
let io = TokioIo::new(stream);
49+
50+
tokio::task::spawn(async move {
51+
if let Err(err) =
52+
http1::Builder::new().serve_connection(io, service_fn(request_handler)).await
53+
{
54+
println!("Error serving connection: {:?}", err);
55+
}
56+
});
57+
}
58+
}
59+
60+
async fn request_handler(
61+
req: Request<hyper::body::Incoming>,
62+
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {
63+
match (req.method(), req.uri().path()) {
64+
// Serve some instructions at /
65+
(&Method::GET, "/") => Ok(Response::new(full(
66+
"Try POSTing data to /request_handler such as: `curl localhost:3000/request_handler -XPOST -d \"PAYJOIN ME\"`",
67+
))),
68+
69+
// Simply echo the body back to the client.
70+
(&Method::POST, "/payjoin") => Ok(Response::new(req.into_body().boxed())),
71+
72+
// Return the 404 Not Found for other routes.
73+
_ => {
74+
let mut not_found = Response::new(
75+
Empty::<Bytes>::new()
76+
.map_err(|never| match never {})
77+
.boxed()
78+
);
79+
*not_found.status_mut() = StatusCode::NOT_FOUND;
80+
Ok(not_found)
81+
}
82+
}
83+
}
84+
85+
fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {
86+
Full::new(chunk.into()).map_err(|never| match never {}).boxed()
87+
}
88+
}

src/wallet.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,11 @@ where
167167
Ok(self.inner.lock().unwrap().get_balance()?)
168168
}
169169

170-
pub(crate) fn list_unspent(&self) -> Result<Vec<bdk::LocalUtxo>, Error> {
170+
pub(crate) fn _list_unspent(&self) -> Result<Vec<bdk::LocalUtxo>, Error> {
171171
Ok(self.inner.lock().unwrap().list_unspent()?)
172172
}
173173

174-
pub(crate) fn wallet_process_psbt(&self, psbt: &Psbt) -> Result<Psbt, Error> {
174+
pub(crate) fn _wallet_process_psbt(&self, psbt: &Psbt) -> Result<Psbt, Error> {
175175
let wallet = self.inner.lock().unwrap();
176176
let mut psbt = psbt.clone();
177177
wallet.sign(&mut psbt, SignOptions::default())?;

0 commit comments

Comments
 (0)