Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Implement RFC-0001 with empty functionality #58

Merged
merged 13 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 10 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
[workspace]
members = [
"crates/*",
members = [
"bindings/tbdex_uniffi", "crates/pfi_exemplar_integration_test",
"crates/tbdex",
]
default-members = [
"crates/*",
"crates/tbdex",
]
resolver = "2"

[workspace.package]
homepage = "https://github.com/TBD54566975/tbdex-rs"
repository = "https://github.com/TBD54566975/tbdex-rs.git"
license-file = "LICENSE"

[workspace.dependencies]
serde = { version = "1.0.193", features = ["derive"] }
serde_json = "1.0.108"
thiserror = "1.0.50"
web5 = { git = "https://github.com/TBD54566975/web5-rs", rev = "f4de14fbada87543a335e1b8dd4442cd21c04db7" }
22 changes: 16 additions & 6 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ default: setup
setup:
#!/bin/bash
if [[ "$(cargo 2>&1)" == *"rustup could not choose a version of cargo to run"* ]]; then
rustup default stable
rustup default 1.78.0
fi

# Build a release variant
Expand All @@ -15,13 +15,23 @@ build: setup

# Run all tests
test: setup
cargo test
cargo test --workspace

# Run linting, look for warnings and/or diffs in the output to correct
lint: setup
cargo clippy --workspace
cargo fmt -- --check
cargo fmt

# Run formatting
fmt: setup
cargo fmt
bind: setup
just bind-kotlin

bind-kotlin: setup
cargo build --release --package tbdex_uniffi
cargo run --package tbdex_uniffi \
--bin uniffi-bindgen \
generate --library target/release/libtbdex_uniffi.dylib \
--language kotlin \
--out-dir target/bindgen-kotlin
cp target/release/libtbdex_uniffi.dylib bound/kt/src/main/resources/natives
cp target/bindgen-kotlin/tbdex/sdk/rust/tbdex.kt bound/kt/src/main/kotlin/tbdex/sdk/rust
cd bound/kt && ./fix-load.sh
25 changes: 25 additions & 0 deletions bindings/tbdex_uniffi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "tbdex_uniffi"
version = "0.1.0"
edition = "2021"
homepage.workspace = true
repository.workspace = true
license-file.workspace = true

[dependencies]
serde_json = { workspace = true }
tbdex = { path = "../../crates/tbdex" }
thiserror = { workspace = true }
uniffi = { version = "0.27.1", features = ["cli"] }
web5 = { workspace = true }
web5_uniffi_wrapper = { git = "https://github.com/TBD54566975/web5-rs", rev = "f4de14fbada87543a335e1b8dd4442cd21c04db7" }

[build-dependencies]
uniffi = { version = "0.27.1", features = ["build"] }

[lib]
crate-type = ["cdylib"]

[[bin]]
name = "uniffi-bindgen"
path = "uniffi-bindgen.rs"
6 changes: 6 additions & 0 deletions bindings/tbdex_uniffi/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// Cargo automatically picks up `build.rs` as a custom build script https://doc.rust-lang.org/cargo/reference/build-scripts.html
/// This build script generates the Rust scaffolded code for UniFFI bindings https://mozilla.github.io/uniffi-rs/tutorial/Rust_scaffolding.html#setup-for-crates-using-udl
/// ex. code like `#[no_mangle]` and `extern "C"` is necessary https://doc.rust-lang.org/nomicon/ffi.html#rust-side
fn main() {
uniffi::generate_scaffolding("src/tbdex.udl").unwrap();
}
99 changes: 99 additions & 0 deletions bindings/tbdex_uniffi/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use serde_json::Error as SerdeJsonError;
use std::sync::{Arc, PoisonError};
use std::{any::type_name, fmt::Debug};
use tbdex::http_client::HttpClientError;
use tbdex::messages::MessageError;
use tbdex::resources::ResourceError;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum RustCoreError {
#[error("{message}")]
Error {
r#type: String,
variant: String,
message: String,
},
}

impl RustCoreError {
pub fn from_poison_error<T>(error: PoisonError<T>, error_type: &str) -> Arc<Self> {
Arc::new(RustCoreError::Error {
r#type: error_type.to_string(),
variant: "PoisonError".to_string(),
message: error.to_string(),
})
}
fn new<T>(error: T) -> Self
where
T: std::error::Error + 'static,
{
Self::Error {
r#type: type_of(&error).to_string(),
variant: variant_name(&error),
message: error.to_string(),
}
}

pub fn error_type(&self) -> String {
match self {
RustCoreError::Error {
r#type: error_type, ..
} => error_type.clone(),
}
}

pub fn variant(&self) -> String {
match self {
RustCoreError::Error {
variant: error_variant,
..
} => error_variant.clone(),
}
}

pub fn message(&self) -> String {
match self {
RustCoreError::Error { message, .. } => message.clone(),
}
}
}

fn type_of<T>(_: &T) -> &'static str {
type_name::<T>()
}

fn variant_name<T>(error: &T) -> String
where
T: Debug,
{
let message = format!("{:?}", error);
let variant_name = message.split('(').next().unwrap_or("UnknownVariant");
variant_name.to_string()
}

impl From<ResourceError> for RustCoreError {
fn from(error: ResourceError) -> Self {
RustCoreError::new(error)
}
}

impl From<MessageError> for RustCoreError {
fn from(error: MessageError) -> Self {
RustCoreError::new(error)
}
}

impl From<HttpClientError> for RustCoreError {
fn from(error: HttpClientError) -> Self {
RustCoreError::new(error)
}
}

impl From<SerdeJsonError> for RustCoreError {
fn from(error: SerdeJsonError) -> Self {
RustCoreError::new(error)
}
}

pub type Result<T> = std::result::Result<T, Arc<RustCoreError>>;
16 changes: 16 additions & 0 deletions bindings/tbdex_uniffi/src/http_client/balances.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::{errors::Result, resources::balance::Balance};
use std::sync::{Arc, RwLock};
use web5_uniffi_wrapper::dids::bearer_did::BearerDid;

pub fn get_balances(pfi_did_uri: String, bearer_did: Arc<BearerDid>) -> Result<Vec<Arc<Balance>>> {
let inner_balances =
tbdex::http_client::balances::get_balances(&pfi_did_uri, &bearer_did.0.clone())
.map_err(|e| Arc::new(e.into()))?;

let balances = inner_balances
.into_iter()
.map(|b| Arc::new(Balance(Arc::new(RwLock::new(b)))))
.collect();

Ok(balances)
}
80 changes: 80 additions & 0 deletions bindings/tbdex_uniffi/src/http_client/exchanges.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::{
errors::Result,
messages::{close::Close, order::Order, order_status::OrderStatus, quote::Quote, rfq::Rfq},
};
use std::sync::{Arc, RwLock};
use tbdex::http_client::exchanges::Exchange as InnerExchange;
use web5_uniffi_wrapper::dids::bearer_did::BearerDid;

pub struct Exchange {
pub rfq: Arc<Rfq>,
pub quote: Option<Arc<Quote>>,
pub order: Option<Arc<Order>>,
pub order_statuses: Option<Vec<Arc<OrderStatus>>>,
pub close: Option<Arc<Close>>,
}

impl Exchange {
pub fn from_inner(inner: InnerExchange) -> Self {
Self {
rfq: Arc::new(Rfq(Arc::new(RwLock::new(inner.rfq.clone())))),
quote: inner
.quote
.as_ref()
.map(|q| Arc::new(Quote(Arc::new(RwLock::new(q.clone()))))),
order: inner
.order
.as_ref()
.map(|o| Arc::new(Order(Arc::new(RwLock::new(o.clone()))))),
order_statuses: inner.order_statuses.as_ref().map(|os| {
os.iter()
.map(|o| Arc::new(OrderStatus(Arc::new(RwLock::new(o.clone())))))
.collect::<Vec<_>>()
}),
close: inner
.close
.as_ref()
.map(|c| Arc::new(Close(Arc::new(RwLock::new(c.clone()))))),
}
}
}

pub fn create_exchange(rfq: Arc<Rfq>, reply_to: Option<String>) -> Result<()> {
tbdex::http_client::exchanges::create_exchange(&rfq.to_inner()?, reply_to)
.map_err(|e| Arc::new(e.into()))?;
Ok(())
}

pub fn submit_order(order: Arc<Order>) -> Result<()> {
tbdex::http_client::exchanges::submit_order(&order.get_data()?)
.map_err(|e| Arc::new(e.into()))?;
Ok(())
}

pub fn submit_close(close: Arc<Close>) -> Result<()> {
tbdex::http_client::exchanges::submit_close(&close.get_data()?)
.map_err(|e| Arc::new(e.into()))?;
Ok(())
}

pub fn get_exchange(
pfi_did_uri: String,
bearer_did: Arc<BearerDid>,
exchange_id: String,
) -> Result<Exchange> {
let inner_exchange = tbdex::http_client::exchanges::get_exchange(
&pfi_did_uri,
&bearer_did.0.clone(),
&exchange_id,
)
.map_err(|e| Arc::new(e.into()))?;

Ok(Exchange::from_inner(inner_exchange))
}

pub fn get_exchanges(pfi_did_uri: String, bearer_did: Arc<BearerDid>) -> Result<Vec<String>> {
let exchange_ids =
tbdex::http_client::exchanges::get_exchanges(&pfi_did_uri, &bearer_did.0.clone())
.map_err(|e| Arc::new(e.into()))?;
Ok(exchange_ids)
}
3 changes: 3 additions & 0 deletions bindings/tbdex_uniffi/src/http_client/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod balances;
pub mod exchanges;
pub mod offerings;
14 changes: 14 additions & 0 deletions bindings/tbdex_uniffi/src/http_client/offerings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use crate::{errors::Result, resources::offering::Offering};
use std::sync::{Arc, RwLock};

pub fn get_offerings(pfi_did_uri: String) -> Result<Vec<Arc<Offering>>> {
let inner_offerings = tbdex::http_client::offerings::get_offerings(&pfi_did_uri)
.map_err(|e| Arc::new(e.into()))?;

let offerings = inner_offerings
.into_iter()
.map(|o| Arc::new(Offering(Arc::new(RwLock::new(o)))))
.collect();

Ok(offerings)
}
Loading
Loading