Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Part 4/N] Interledger ILDCP: Futures 0.3 Transition #597

Merged
merged 6 commits into from
Jan 29, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ members = [
# "./crates/interledger-btp",
# "./crates/interledger-ccp",
# "./crates/interledger-http",
# "./crates/interledger-ildcp",
"./crates/interledger-ildcp",
"./crates/interledger-packet",
"./crates/interledger-router",
"./crates/interledger-service",
Expand Down
7 changes: 6 additions & 1 deletion crates/interledger-ildcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ repository = "https://github.com/interledger-rs/interledger-rs"
[dependencies]
bytes = { version = "0.4.12", default-features = false }
byteorder = { version = "1.3.2", default-features = false }
futures = { version = "0.1.29", default-features = false }
futures = { version = "0.3", default-features = false }
interledger-packet = { path = "../interledger-packet", version = "^0.4.0", default-features = false }
interledger-service = { path = "../interledger-service", version = "^0.4.0", default-features = false }
lazy_static = { version = "1.4.0", default-features = false }
log = { version = "0.4.8", default-features = false }
async-trait = "0.1.22"

[dev-dependencies]
tokio = { version = "0.2.6", features = ["macros","rt-core"]}
uuid = { version = "0.8.1", features = ["v4"] }
33 changes: 15 additions & 18 deletions crates/interledger-ildcp/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
use super::packet::*;
use futures::Future;
use futures::future::TryFutureExt;
use interledger_service::*;
use log::{debug, error};
use std::convert::TryFrom;

/// Get the ILP address and asset details for a given account.
pub fn get_ildcp_info<S, A>(
service: &mut S,
account: A,
) -> impl Future<Item = IldcpResponse, Error = ()>
/// Sends an ILDCP Request to the provided service from the provided account
/// and receives the account's ILP address and asset details
pub async fn get_ildcp_info<S, A>(service: &mut S, account: A) -> Result<IldcpResponse, ()>
where
S: IncomingService<A>,
A: Account,
{
let prepare = IldcpRequest {}.to_prepare();
service
let fulfill = service
.handle_request(IncomingRequest {
from: account,
prepare,
})
.map_err(|err| error!("Error getting ILDCP info: {:?}", err))
.and_then(|fulfill| {
let response =
IldcpResponse::try_from(fulfill.into_data().freeze()).map_err(|err| {
error!(
"Unable to parse ILDCP response from fulfill packet: {:?}",
err
);
})?;
debug!("Got ILDCP response: {:?}", response);
Ok(response)
})
.await?;

let response = IldcpResponse::try_from(fulfill.into_data().freeze()).map_err(|err| {
error!(
"Unable to parse ILDCP response from fulfill packet: {:?}",
err
);
})?;
debug!("Got ILDCP response: {:?}", response);
Ok(response)
}
8 changes: 8 additions & 0 deletions crates/interledger-ildcp/src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ pub fn is_ildcp_request(prepare: &Prepare) -> bool {
&& prepare.destination() == *ILDCP_DESTINATION
}

/// ILDCP Requests are sent to peers to receive an ILDCP Response
/// which contains details about how the peer has configured our account
/// (this is just a newtype to type-safe serialize to a Prepare packet)
#[derive(Debug, Default)]
pub struct IldcpRequest {}

Expand All @@ -55,11 +58,16 @@ impl From<IldcpRequest> for Prepare {
}
}

/// The response to an ILDCP Request.
#[derive(Clone, PartialEq)]
pub struct IldcpResponse {
/// Serialized buffer of the response
buffer: Bytes,
/// The asset scale corresponding to the requested account
asset_scale: u8,
/// The offset after which the asset code is stored in the buffer
asset_code_offset: usize,
/// The ILP Address we have assigned to the requested account
ilp_address: Address,
}

Expand Down
77 changes: 69 additions & 8 deletions crates/interledger-ildcp/src/server.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::packet::*;
use super::Account;
use futures::future::ok;
use async_trait::async_trait;
use interledger_packet::*;
use interledger_service::*;
use log::debug;
Expand All @@ -27,14 +27,13 @@ where
}
}

#[async_trait]
impl<I, A> IncomingService<A> for IldcpService<I, A>
where
I: IncomingService<A>,
I: IncomingService<A> + Send,
A: Account,
{
type Future = BoxedIlpFuture;

fn handle_request(&mut self, request: IncomingRequest<A>) -> Self::Future {
async fn handle_request(&mut self, request: IncomingRequest<A>) -> IlpResult {
if is_ildcp_request(&request.prepare) {
let from = request.from.ilp_address();
let builder = IldcpResponseBuilder {
Expand All @@ -44,10 +43,72 @@ where
};
debug!("Responding to query for ildcp info by account: {:?}", from);
let response = builder.build();
let fulfill = Fulfill::from(response);
Box::new(ok(fulfill))
Ok(Fulfill::from(response))
} else {
Box::new(self.next.handle_request(request))
self.next.handle_request(request).await
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::get_ildcp_info;
use lazy_static::lazy_static;
use std::str::FromStr;
use uuid::Uuid;

lazy_static! {
pub static ref ALICE: Username = Username::from_str("alice").unwrap();
pub static ref EXAMPLE_ADDRESS: Address = Address::from_str("example.alice").unwrap();
}

#[derive(Clone, Debug, Copy)]
struct TestAccount;

impl Account for TestAccount {
fn id(&self) -> Uuid {
Uuid::new_v4()
}

fn username(&self) -> &Username {
&ALICE
}

fn asset_scale(&self) -> u8 {
9
}

fn asset_code(&self) -> &str {
"XYZ"
}

fn ilp_address(&self) -> &Address {
&EXAMPLE_ADDRESS
}
}

#[tokio::test]
async fn handles_request() {
let from = TestAccount;
let prepare = IldcpRequest {}.to_prepare();
let req = IncomingRequest { from, prepare };
let mut service = IldcpService::new(incoming_service_fn(|_| {
Err(RejectBuilder {
code: ErrorCode::F02_UNREACHABLE,
message: b"No other incoming handler!",
data: &[],
triggered_by: None,
}
.build())
}));

let result = service.handle_request(req).await.unwrap();
assert_eq!(result.data().len(), 19);

let ildpc_info = get_ildcp_info(&mut service, from).await.unwrap();
assert_eq!(ildpc_info.ilp_address(), EXAMPLE_ADDRESS.clone());
assert_eq!(ildpc_info.asset_code(), b"XYZ");
assert_eq!(ildpc_info.asset_scale(), 9);
}
}