diff --git a/src/core/pay_request.rs b/src/core/pay_request.rs index cdd8974..dc35737 100644 --- a/src/core/pay_request.rs +++ b/src/core/pay_request.rs @@ -180,6 +180,17 @@ impl std::str::FromStr for CallbackResponse { } } +impl std::fmt::Display for CallbackResponse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let cr = ser::CallbackResponse { + disposable: self.disposable, + pr: &self.pr, + }; + + f.write_str(&miniserde::json::to_string(&cr)) + } +} + mod ser { use crate::serde::Url; use miniserde::Serialize; @@ -199,6 +210,12 @@ mod ser { #[serde(rename = "successAction")] pub success_action: Option>>, } + + #[derive(Serialize)] + pub(super) struct CallbackResponse<'a> { + pub pr: &'a str, + pub disposable: bool, + } } mod de { diff --git a/src/server.rs b/src/server.rs index 9529e45..10bf2a5 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,33 +1,86 @@ use axum::{http::StatusCode, routing::get, Router}; use std::future::Future; -#[must_use] -pub fn builder

() -> Server

{ - Server { pay_request: None } +pub struct Server { + pay_request_query: PQ, + pay_request_callback: PC, } -pub struct Server

{ - pub pay_request: Option

, +impl Default + for Server< + unimplemented::Handler, + unimplemented::Handler, + > +{ + fn default() -> Self { + Server { + pay_request_query: unimplemented::handler, + pay_request_callback: unimplemented::handler, + } + } } -impl Server

+impl Server { + pub fn pay_request( + self, + pay_request_query: PQ2, + pay_request_callback: PC2, + ) -> Server { + Server { + pay_request_query, + pay_request_callback, + } + } +} + +impl Server where - P: 'static + Send + Clone + Fn() -> PFut, - PFut: Send + Future>, + PQ: 'static + Send + Clone + Fn() -> PQFut, + PQFut: Send + Future>, + PC: 'static + Send + Clone + Fn() -> PCFut, + PCFut: Send + Future>, { pub fn build(self) -> Router<()> { - let mut router = Router::new(); - - if let Some(p) = self.pay_request { - router = router.route( + Router::new() + .route( "/lnurlp", get(move || { - let p = p.clone(); - async move { p().await.map(|a| a.to_string()) } + let pq = self.pay_request_query.clone(); + async move { pq().await.map(|a| a.to_string()) } + }), + ) + .route( + "/lnurlp/callback", + get(move || { + let pc = self.pay_request_callback.clone(); + async move { pc().await.map(|a| a.to_string()) } }), - ); + ) + } +} + +mod unimplemented { + use axum::http::StatusCode; + use std::{ + future::Future, + marker::PhantomData, + pin::Pin, + task::{Context, Poll}, + }; + + pub(super) type Handler = fn() -> Unimplemented; + + pub struct Unimplemented(PhantomData); + + impl Future for Unimplemented { + type Output = Result; + + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Err(StatusCode::NOT_IMPLEMENTED)) } + } - router + pub(super) fn handler() -> Unimplemented { + Unimplemented(PhantomData) } } diff --git a/tests/lud06.rs b/tests/lud06.rs index b4ba913..d8b23a1 100644 --- a/tests/lud06.rs +++ b/tests/lud06.rs @@ -9,29 +9,32 @@ async fn test() { let query_url = format!("http://{addr}/lnurlp"); let callback_url = url::Url::parse(&format!("http://{addr}/lnurlp/callback")).expect("url"); - let router = { - let mut router = lnurlkit::server::builder(); - - router.pay_request = Some(move || { - let callback = callback_url.clone(); - - async { - Ok(lnurlkit::core::pay_request::PayRequest { - callback, - short_description: String::from("today i become death"), - long_description: Some(String::from("the destroyer of worlds")), - success_action: None, - jpeg: None, - png: None, - comment_size: 0, - min: 314, - max: 315, + let router = lnurlkit::server::Server::default() + .pay_request( + move || { + let callback = callback_url.clone(); + async { + Ok(lnurlkit::core::pay_request::PayRequest { + callback, + short_description: String::from("today i become death"), + long_description: Some(String::from("the destroyer of worlds")), + success_action: None, + jpeg: None, + png: None, + comment_size: 0, + min: 314, + max: 315, + }) + } + }, + move || async { + Ok(lnurlkit::core::pay_request::CallbackResponse { + pr: String::from("pierre"), + disposable: false, }) - } - }); - - router.build() - }; + }, + ) + .build(); tokio::spawn(async move { axum::serve(listener, router).await.expect("serve"); @@ -57,9 +60,13 @@ async fn test() { assert_eq!(pr.core.min, 314); assert_eq!(pr.core.max, 315); assert_eq!(pr.core.short_description, "today i become death"); - assert_eq!(pr.core.long_description.unwrap(), "the destroyer of worlds"); + assert_eq!( + pr.core.long_description.as_ref().unwrap(), + "the destroyer of worlds" + ); - // let invoice = pr.callback("comment", 123000).await.expect("callback"); + let invoice = pr.callback("comment", 314).await.expect("callback"); - // println!("{invoice:?}"); + assert_eq!(invoice.pr, "pierre"); + assert!(!invoice.disposable); }