Skip to content

Commit

Permalink
refactor: split client/server structs inside core
Browse files Browse the repository at this point in the history
  • Loading branch information
lsunsi committed Dec 9, 2023
1 parent 1e12919 commit ee5e841
Show file tree
Hide file tree
Showing 20 changed files with 1,569 additions and 1,379 deletions.
30 changes: 15 additions & 15 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,30 @@ pub enum Query<'a> {
#[derive(Clone, Debug)]
pub struct Channel<'a> {
client: &'a reqwest::Client,
pub core: crate::channel::Query,
pub core: crate::channel::client::Query,
}

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

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

impl Channel<'_> {
/// # Errors
///
/// Returns errors on network or deserialization failures.
pub async fn callback_accept(
self,
remoteid: String,
&self,
remoteid: &str,
private: bool,
) -> Result<crate::channel::CallbackResponse, &'static str> {
) -> Result<crate::channel::client::CallbackResponse, &'static str> {
let callback = self.core.callback_accept(remoteid, private).url();

let response = self
Expand All @@ -73,9 +73,9 @@ impl Channel<'_> {
///
/// Returns errors on network or deserialization failures.
pub async fn callback_cancel(
self,
remoteid: String,
) -> Result<crate::channel::CallbackResponse, &'static str> {
&self,
remoteid: &str,
) -> Result<crate::channel::client::CallbackResponse, &'static str> {
let callback = self.core.callback_cancel(remoteid).url();

let response = self
Expand All @@ -95,10 +95,10 @@ impl Pay<'_> {
///
/// Returns errors on network or deserialization failures.
pub async fn callback(
self,
&self,
millisatoshis: u64,
comment: String,
) -> Result<crate::pay::CallbackResponse, &'static str> {
comment: &str,
) -> Result<crate::pay::client::CallbackResponse, &'static str> {
let callback = self.core.callback(millisatoshis, comment).url();

let response = self
Expand All @@ -118,9 +118,9 @@ impl Withdraw<'_> {
///
/// Returns errors on network or deserialization failures.
pub async fn callback(
self,
pr: String,
) -> Result<crate::withdraw::CallbackResponse, &'static str> {
&self,
pr: &str,
) -> Result<crate::withdraw::client::CallbackResponse, &'static str> {
let callback = self.core.callback(pr).url();

let response = self
Expand Down
6 changes: 3 additions & 3 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ fn resolve_address(s: &str) -> Result<url::Url, &'static str> {

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

impl std::str::FromStr for Query {
Expand Down
281 changes: 2 additions & 279 deletions src/core/channel.rs
Original file line number Diff line number Diff line change
@@ -1,280 +1,3 @@
pub const TAG: &str = "channelRequest";

#[derive(Clone, Debug)]
pub struct Query {
pub callback: url::Url,
pub uri: String,
pub k1: String,
}

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

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

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

impl std::fmt::Display for Query {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&miniserde::json::to_string(&ser::Query {
tag: TAG,
callback: crate::serde::Url(std::borrow::Cow::Borrowed(&self.callback)),
uri: &self.uri,
k1: &self.k1,
}))
}
}

impl Query {
#[must_use]
pub fn callback_accept(self, remoteid: String, private: bool) -> CallbackRequest {
CallbackRequest::Accept {
url: self.callback,
k1: self.k1,
remoteid,
private,
}
}

#[must_use]
pub fn callback_cancel(self, remoteid: String) -> CallbackRequest {
CallbackRequest::Cancel {
url: self.callback,
k1: self.k1,
remoteid,
}
}
}

pub enum CallbackRequest {
Cancel {
url: url::Url,
remoteid: String,
k1: String,
},
Accept {
url: url::Url,
remoteid: String,
private: bool,
k1: String,
},
}

impl CallbackRequest {
#[must_use]
pub fn url(self) -> url::Url {
match self {
CallbackRequest::Cancel {
mut url,
remoteid,
k1,
} => {
let query = [
("k1", k1),
("remoteid", remoteid),
("cancel", String::from("1")),
];

url.query_pairs_mut().extend_pairs(query);
url
}
CallbackRequest::Accept {
mut url,
remoteid,
private,
k1,
} => {
let query = [
("k1", k1),
("remoteid", remoteid),
("private", String::from(if private { "1" } else { "0" })),
];

url.query_pairs_mut().extend_pairs(query);
url
}
}
}
}

#[derive(Debug)]
pub enum CallbackResponse {
Error(String),
Ok,
}

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

fn from_str(s: &str) -> Result<Self, Self::Err> {
let map = miniserde::json::from_str::<std::collections::BTreeMap<String, String>>(s)
.map_err(|_| "bad json")?;

match map.get("status").map(|s| s as &str) {
Some("OK") => Ok(CallbackResponse::Ok),
Some("ERROR") => Ok(CallbackResponse::Error(
map.get("reason").cloned().unwrap_or_default(),
)),
_ => Err("bad status field"),
}
}
}

impl std::fmt::Display for CallbackResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut map = std::collections::BTreeMap::new();

match self {
CallbackResponse::Error(reason) => {
map.insert("status", "ERROR");
map.insert("reason", reason);
}
CallbackResponse::Ok => {
map.insert("status", "OK");
}
}

f.write_str(&miniserde::json::to_string(&map))
}
}

mod ser {
use crate::serde::Url;
use miniserde::Serialize;

#[derive(Serialize)]
pub(super) struct Query<'a> {
pub tag: &'static str,
pub callback: Url<'a>,
pub uri: &'a str,
pub k1: &'a str,
}
}

mod de {
use crate::serde::Url;
use miniserde::Deserialize;

#[derive(Deserialize)]
pub(super) struct Query {
pub callback: Url<'static>,
pub uri: String,
pub k1: String,
}
}

#[cfg(test)]
mod tests {
use std::assert_eq;

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

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

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

#[test]
fn query_render() {
let query = super::Query {
callback: url::Url::parse("https://yuri/?o=callback").expect("url"),
uri: String::from("noh@ipe:porta"),
k1: String::from("caum"),
};

let json = r#"{"tag":"channelRequest","callback":"https://yuri/?o=callback","uri":"noh@ipe:porta","k1":"caum"}"#;
assert_eq!(query.to_string(), json);
}

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

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

assert_eq!(
url.to_string(),
"https://yuri/?o=callback&k1=caum&remoteid=idremoto&private=1"
);

let url = parsed
.callback_accept(String::from("idremoto"), false)
.url();

assert_eq!(
url.to_string(),
"https://yuri/?o=callback&k1=caum&remoteid=idremoto&private=0"
);
}

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

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

assert_eq!(
url.to_string(),
"https://yuri/?o=callback&k1=caum&remoteid=idremoto&cancel=1"
);
}

#[test]
fn callback_response_parse() {
assert!(matches!(
r#"{ "status": "OK"}"#.parse().unwrap(),
super::CallbackResponse::Ok
));

assert!(matches!(
r#"{ "status": "ERROR", "reason": "razao" }"#.parse().unwrap(),
super::CallbackResponse::Error(r) if r == "razao"
));
}

#[test]
fn callback_response_render() {
assert_eq!(
super::CallbackResponse::Ok.to_string(),
r#"{"status":"OK"}"#
);
assert_eq!(
super::CallbackResponse::Error(String::from("razao")).to_string(),
r#"{"reason":"razao","status":"ERROR"}"#
);
}
}
pub mod client;
pub mod server;
Loading

0 comments on commit ee5e841

Please sign in to comment.