Skip to content

Commit

Permalink
Improve server and testing for lud06
Browse files Browse the repository at this point in the history
  • Loading branch information
lsunsi committed Dec 4, 2023
1 parent eabaa91 commit e6ca351
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 41 deletions.
17 changes: 17 additions & 0 deletions src/core/pay_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -199,6 +210,12 @@ mod ser {
#[serde(rename = "successAction")]
pub success_action: Option<BTreeMap<&'static str, std::borrow::Cow<'a, str>>>,
}

#[derive(Serialize)]
pub(super) struct CallbackResponse<'a> {
pub pr: &'a str,
pub disposable: bool,
}
}

mod de {
Expand Down
85 changes: 69 additions & 16 deletions src/server.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,86 @@
use axum::{http::StatusCode, routing::get, Router};
use std::future::Future;

#[must_use]
pub fn builder<P>() -> Server<P> {
Server { pay_request: None }
pub struct Server<PQ, PC> {
pay_request_query: PQ,
pay_request_callback: PC,
}

pub struct Server<P> {
pub pay_request: Option<P>,
impl Default
for Server<
unimplemented::Handler<crate::core::pay_request::PayRequest>,
unimplemented::Handler<crate::core::pay_request::CallbackResponse>,
>
{
fn default() -> Self {
Server {
pay_request_query: unimplemented::handler,
pay_request_callback: unimplemented::handler,
}
}
}

impl<P, PFut> Server<P>
impl<PQ, PC> Server<PQ, PC> {
pub fn pay_request<PQ2, PC2>(
self,
pay_request_query: PQ2,
pay_request_callback: PC2,
) -> Server<PQ2, PC2> {
Server {
pay_request_query,
pay_request_callback,
}
}
}

impl<PQ, PQFut, PC, PCFut> Server<PQ, PC>
where
P: 'static + Send + Clone + Fn() -> PFut,
PFut: Send + Future<Output = Result<crate::core::pay_request::PayRequest, StatusCode>>,
PQ: 'static + Send + Clone + Fn() -> PQFut,
PQFut: Send + Future<Output = Result<crate::core::pay_request::PayRequest, StatusCode>>,
PC: 'static + Send + Clone + Fn() -> PCFut,
PCFut: Send + Future<Output = Result<crate::core::pay_request::CallbackResponse, StatusCode>>,
{
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<T> = fn() -> Unimplemented<T>;

pub struct Unimplemented<T>(PhantomData<T>);

impl<T> Future for Unimplemented<T> {
type Output = Result<T, StatusCode>;

fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<T, StatusCode>> {
Poll::Ready(Err(StatusCode::NOT_IMPLEMENTED))
}
}

router
pub(super) fn handler<T>() -> Unimplemented<T> {
Unimplemented(PhantomData)
}
}
57 changes: 32 additions & 25 deletions tests/lud06.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);
}

0 comments on commit e6ca351

Please sign in to comment.