Skip to content

Commit

Permalink
refactor: leverage serde for serding the query strings
Browse files Browse the repository at this point in the history
  • Loading branch information
lsunsi committed Dec 11, 2023
1 parent 682fe4d commit 749f1d5
Show file tree
Hide file tree
Showing 22 changed files with 353 additions and 305 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ base64 = { version = "0.21.0", features = ["std"], default-features = false }
bech32 = { version = "0.9.0", default-features = false }
serde = { version = "1.0.0", features = ["derive"], default-features = false }
serde_json = { version = "1.0.0", features = ["std"], default-features = false }
serde_urlencoded = { version = "0.7.0", default-features = false }
url = { version = "2.5.0", features = ["serde"], default-features = false }

axum = { version = "0.7.0", default-features = false, optional = true }
Expand Down
20 changes: 10 additions & 10 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@ impl Client {
/// # Errors
///
/// Returns errors on network or deserialization failures.
pub async fn query(&self, s: &str) -> Result<Query, &'static str> {
pub async fn query(&self, s: &str) -> Result<Response, &'static str> {
let url = crate::resolve(s)?;

let client = &self.0;
let response = client.get(url).send().await.map_err(|_| "request failed")?;
let text = response.text().await.map_err(|_| "body failed")?;

text.parse::<crate::Query>()
text.parse::<crate::Response>()
.map_err(|_| "parse failed")
.map(|query| match query {
crate::Query::Channel(core) => Query::Channel(Channel { client, core }),
crate::Query::Pay(core) => Query::Pay(Pay { client, core }),
crate::Query::Withdraw(core) => Query::Withdraw(Withdraw { client, core }),
crate::Response::Channel(core) => Response::Channel(Channel { client, core }),
crate::Response::Pay(core) => Response::Pay(Pay { client, core }),
crate::Response::Withdraw(core) => Response::Withdraw(Withdraw { client, core }),
})
}
}

#[derive(Clone, Debug)]
pub enum Query<'a> {
pub enum Response<'a> {
Channel(Channel<'a>),
Pay(Pay<'a>),
Withdraw(Withdraw<'a>),
Expand All @@ -32,19 +32,19 @@ pub enum Query<'a> {
#[derive(Clone, Debug)]
pub struct Channel<'a> {
client: &'a reqwest::Client,
pub core: crate::channel::client::Query,
pub core: crate::channel::client::Response,
}

#[derive(Clone, Debug)]
pub struct Pay<'a> {
client: &'a reqwest::Client,
pub core: crate::pay::client::Query,
pub core: crate::pay::client::Response,
}

#[derive(Clone, Debug)]
pub struct Withdraw<'a> {
client: &'a reqwest::Client,
pub core: crate::withdraw::client::Query,
pub core: crate::withdraw::client::Response,
}

impl Channel<'_> {
Expand Down Expand Up @@ -97,7 +97,7 @@ impl Pay<'_> {
pub async fn callback(
&self,
millisatoshis: u64,
comment: &str,
comment: Option<&str>,
) -> Result<crate::pay::client::CallbackResponse, &'static str> {
let callback = self.core.callback(millisatoshis, comment);

Expand Down
16 changes: 8 additions & 8 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ fn resolve_address(s: &str) -> Result<url::Url, &'static str> {
}

#[derive(Debug)]
pub enum Query {
Channel(channel::client::Query),
Pay(pay::client::Query),
Withdraw(withdraw::client::Query),
pub enum Response {
Channel(channel::client::Response),
Pay(pay::client::Response),
Withdraw(withdraw::client::Response),
}

impl std::str::FromStr for Query {
impl std::str::FromStr for Response {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Expand All @@ -88,13 +88,13 @@ impl std::str::FromStr for Query {

if tag.tag == channel::TAG {
let cr = s.parse().map_err(|_| "deserialize data failed")?;
Ok(Query::Channel(cr))
Ok(Response::Channel(cr))
} else if tag.tag == pay::TAG {
let pr = s.parse().map_err(|_| "deserialize data failed")?;
Ok(Query::Pay(pr))
Ok(Response::Pay(pr))
} else if tag.tag == withdraw::TAG {
let wr = s.parse().map_err(|_| "deserialize data failed")?;
Ok(Query::Withdraw(wr))
Ok(Response::Withdraw(wr))
} else {
Err("unknown tag")
}
Expand Down
33 changes: 33 additions & 0 deletions src/core/channel.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
pub const TAG: &str = "channelRequest";
pub mod client;
pub mod server;

mod serde {
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
#[serde(untagged)]
pub(super) enum CallbackQuery<'a> {
Accept {
k1: &'a str,
remoteid: &'a str,
private: ZeroOrOne,
},
Cancel {
k1: &'a str,
remoteid: &'a str,
cancel: OneOnly,
},
}

#[derive(Deserialize, Serialize)]
pub(super) enum OneOnly {
#[serde(rename = "1")]
One,
}

#[derive(Deserialize, Serialize)]
pub(super) enum ZeroOrOne {
#[serde(rename = "0")]
Zero,
#[serde(rename = "1")]
One,
}
}
89 changes: 48 additions & 41 deletions src/core/channel/client.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
#[derive(Clone, Debug)]
pub struct Query {
pub struct Response {
callback: url::Url,
pub uri: String,
k1: String,
}

impl std::str::FromStr for Query {
impl std::str::FromStr for Response {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let d: de::Query = serde_json::from_str(s).map_err(|_| "deserialize failed")?;
let d: de::Response = serde_json::from_str(s).map_err(|_| "deserialize failed")?;

Ok(Query {
Ok(Response {
callback: d.callback,
uri: d.uri,
k1: d.k1,
})
}
}

impl Query {
impl Response {
#[must_use]
pub fn callback_accept<'a>(&'a self, remoteid: &'a str, private: bool) -> CallbackRequest<'a> {
CallbackRequest::Accept {
pub fn callback_accept<'a>(&'a self, remoteid: &'a str, private: bool) -> CallbackQuery<'a> {
CallbackQuery::Accept {
url: &self.callback,
k1: &self.k1,
remoteid,
Expand All @@ -31,8 +31,8 @@ impl Query {
}

#[must_use]
pub fn callback_cancel<'a>(&'a self, remoteid: &'a str) -> CallbackRequest<'a> {
CallbackRequest::Cancel {
pub fn callback_cancel<'a>(&'a self, remoteid: &'a str) -> CallbackQuery<'a> {
CallbackQuery::Cancel {
url: &self.callback,
k1: &self.k1,
remoteid,
Expand All @@ -41,46 +41,53 @@ impl Query {
}

#[derive(Clone, Debug)]
pub enum CallbackRequest<'a> {
pub enum CallbackQuery<'a> {
Accept {
url: &'a url::Url,
remoteid: &'a str,
k1: &'a str,
remoteid: &'a str,
private: bool,
},
Cancel {
url: &'a url::Url,
remoteid: &'a str,
k1: &'a str,
remoteid: &'a str,
},
}

impl std::fmt::Display for CallbackRequest<'_> {
impl std::fmt::Display for CallbackQuery<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CallbackRequest::Cancel { url, remoteid, k1 } => {
let mut url = (*url).clone();
let query = [("k1", *k1), ("remoteid", remoteid), ("cancel", "1")];
url.query_pairs_mut().extend_pairs(query);
f.write_str(url.as_str())
}
CallbackRequest::Accept {
let (url, query) = match self {
CallbackQuery::Accept {
url,
k1,
remoteid,
private,
k1,
} => {
let query = [
("k1", *k1),
("remoteid", remoteid),
("private", if *private { "1" } else { "0" }),
];

let mut url = (*url).clone();
url.query_pairs_mut().extend_pairs(query);
f.write_str(url.as_str())
}
}
} => (
url,
super::serde::CallbackQuery::Accept {
k1,
remoteid,
private: if *private {
super::serde::ZeroOrOne::One
} else {
super::serde::ZeroOrOne::Zero
},
},
),
CallbackQuery::Cancel { url, k1, remoteid } => (
url,
super::serde::CallbackQuery::Cancel {
k1,
remoteid,
cancel: super::serde::OneOnly::One,
},
),
};

let querystr = serde_urlencoded::to_string(query).map_err(|_| std::fmt::Error)?;
let sep = if url.query().is_some() { '&' } else { '?' };
write!(f, "{url}{sep}{querystr}")
}
}

Expand Down Expand Up @@ -113,7 +120,7 @@ mod de {
use url::Url;

#[derive(Deserialize)]
pub(super) struct Query {
pub(super) struct Response {
pub callback: Url,
pub uri: String,
pub k1: String,
Expand All @@ -123,29 +130,29 @@ mod de {
#[cfg(test)]
mod tests {
#[test]
fn query_parse() {
fn response_parse() {
let input = r#"{
"callback": "https://yuri?o=callback",
"uri": "noh@ipe:porta",
"k1": "caum"
}"#;

let parsed = input.parse::<super::Query>().expect("parse");
let parsed = input.parse::<super::Response>().expect("parse");

assert_eq!(parsed.callback.as_str(), "https://yuri/?o=callback");
assert_eq!(parsed.uri, "noh@ipe:porta");
assert_eq!(parsed.k1, "caum");
}

#[test]
fn callback_request_accept_render() {
fn callback_query_accept_render() {
let input = r#"{
"callback": "https://yuri?o=callback",
"uri": "noh@ipe:porta",
"k1": "caum"
}"#;

let parsed = input.parse::<super::Query>().expect("parse");
let parsed = input.parse::<super::Response>().expect("parse");
let url = parsed.callback_accept("idremoto", true);

assert_eq!(
Expand All @@ -162,14 +169,14 @@ mod tests {
}

#[test]
fn callback_request_cancel_render() {
fn callback_query_cancel_render() {
let input = r#"{
"callback": "https://yuri?o=callback",
"uri": "noh@ipe:porta",
"k1": "caum"
}"#;

let parsed = input.parse::<super::Query>().expect("parse");
let parsed = input.parse::<super::Response>().expect("parse");
let url = parsed.callback_cancel("idremoto");

assert_eq!(
Expand Down
Loading

0 comments on commit 749f1d5

Please sign in to comment.