Skip to content

Commit c40bda5

Browse files
authored
API prototype (#1628)
* Prototype a new api strategy - increase code sharing between grpc and http - set up our codebase for simplifying traits in xmtp_mls - make it easier to add/remove/modify api - make api more rust idiomatic * fix header panic * temporarily exclude d14n * fmt toml
1 parent ece46c7 commit c40bda5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3422
-1340
lines changed

.github/workflows/test-http-api.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ jobs:
4747
- name: build tests
4848
run: cargo nextest run --config-file ".cargo/nextest.toml" --no-run --tests --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --features http-api
4949
- name: cargo test
50-
run: cargo nextest run --config-file ".cargo/nextest.toml" --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --features http-api --test-threads 2
50+
run: cargo nextest run --config-file ".cargo/nextest.toml" --workspace --exclude xmtp_api_grpc --exclude xmtpv3 --exclude bindings_node --exclude bindings_wasm --exclude xmtp_api_d14n --features http-api --test-threads 2

Cargo.lock

+21-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ members = [
1818
"xmtp_debug",
1919
"xmtp_content_types",
2020
"common",
21+
"xmtp_api_d14n",
2122
]
2223

2324
# Make the feature resolver explicit.
@@ -71,8 +72,8 @@ openssl-sys = { version = "0.9", features = ["vendored"] }
7172
parking_lot = "0.12.3"
7273
pbjson = "0.7.0"
7374
pbjson-types = "0.7.0"
74-
prost = "^0.13"
75-
prost-types = "^0.13"
75+
prost = { version = "^0.13", default-features = false }
76+
prost-types = { version = "^0.13", default-features = false }
7677
rand = "0.8.5"
7778
regex = "1.10.4"
7879
rustc-hex = "2.1.0"

common/src/retry.rs

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use std::sync::{
2424
Arc,
2525
};
2626

27+
pub type BoxedRetry = Retry<Box<dyn Strategy>, Box<dyn Strategy>>;
28+
2729
pub struct NotSpecialized;
2830

2931
/// Specifies which errors are retryable.

common/src/stream_handles.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ pub enum StreamHandleError {
1313
ChannelClosed,
1414
#[error("The stream was closed")]
1515
StreamClosed,
16-
#[error(transparent)]
17-
JoinHandleError(#[from] tokio::task::JoinError),
1816
#[error("Stream Cancelled")]
1917
Cancelled,
2018
#[error("Stream Panicked With {0}")]
2119
Panicked(String),
20+
#[cfg(not(target_arch = "wasm32"))]
21+
#[error(transparent)]
22+
JoinHandleError(#[from] tokio::task::JoinError),
2223
}
2324
/// A handle to a spawned Stream
2425
/// the spawned stream can be 'joined` by awaiting its Future implementation.

xmtp_api_d14n/Cargo.toml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "xmtp_api_d14n"
3+
edition = "2021"
4+
license.workspace = true
5+
version.workspace = true
6+
7+
[dependencies]
8+
derive_builder = "0.20"
9+
once_cell.workspace = true
10+
parking_lot.workspace = true
11+
prost.workspace = true
12+
prost-types.workspace = true
13+
xmtp_proto.workspace = true
14+
15+
[dev-dependencies]
16+
xmtp_api_grpc.workspace = true
17+
tokio.workspace = true
18+
19+
[features]
20+
http-api = []
21+
grpc-api = []

xmtp_api_d14n/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Decentralization API for XMTP
2+
3+
Backwards-compatible with non-d14n endpoints (endpoints/v3/*), includes new d14n
4+
endpoints (endpoints/d14n).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use derive_builder::Builder;
2+
use prost::Message;
3+
use std::borrow::Cow;
4+
use xmtp_proto::traits::{BodyError, Endpoint};
5+
use xmtp_proto::xmtp::mls::api::v1::FetchKeyPackagesRequest;
6+
use xmtp_proto::xmtp::xmtpv4::message_api::FILE_DECRIPTOR_SET;
7+
use xmtp_proto::xmtp::xmtpv4::message_api::{GetInboxIdsRequest, GetInboxIdsResponse};
8+
9+
#[derive(Debug, Builder, Default)]
10+
#[builder(setter(strip_option))]
11+
pub struct GetInboxIds {
12+
#[builder(setter(into))]
13+
envelopes: Vec<ClientEnvelope>,
14+
}
15+
16+
impl GetInboxIds {
17+
pub fn builder() -> GetInboxIdsBuilder {
18+
Default::default()
19+
}
20+
}
21+
22+
impl Endpoint for GetInboxIds {
23+
type Output = GetInboxIdsResponse;
24+
25+
fn http_endpoint(&self) -> Cow<'static, str> {
26+
todo!()
27+
}
28+
29+
fn grpc_endpoint(&self) -> Cow<'static, str> {
30+
crate::path_and_query::<PublishClientEnvelopesRequest>(FILE_DESCRIPTOR_SET)
31+
}
32+
33+
fn body(&self) -> Result<Vec<u8>, BodyError> {
34+
Ok(PublishClientEnvelopesRequest {
35+
envelopes: self.envelopes.clone(),
36+
}
37+
.encode_to_vec())
38+
}
39+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod publish_client_envelopes;
2+
pub use publish_client_envelopes::*;
3+
4+
mod query_envelopes;
5+
pub use query_envelopes::*;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use derive_builder::Builder;
2+
use prost::Message;
3+
use std::borrow::Cow;
4+
use xmtp_proto::traits::{BodyError, Endpoint};
5+
use xmtp_proto::xmtp::xmtpv4::envelopes::ClientEnvelope;
6+
use xmtp_proto::xmtp::xmtpv4::payer_api::PublishClientEnvelopesRequest;
7+
use xmtp_proto::xmtp::xmtpv4::payer_api::FILE_DESCRIPTOR_SET;
8+
9+
#[derive(Debug, Builder, Default)]
10+
#[builder(setter(strip_option))]
11+
pub struct PublishClientEnvelopes {
12+
#[builder(setter(into))]
13+
envelopes: Vec<ClientEnvelope>,
14+
}
15+
16+
impl PublishClientEnvelopes {
17+
pub fn builder() -> PublishClientEnvelopesBuilder {
18+
Default::default()
19+
}
20+
}
21+
22+
impl Endpoint for PublishClientEnvelopes {
23+
type Output = ();
24+
fn http_endpoint(&self) -> Cow<'static, str> {
25+
todo!()
26+
}
27+
28+
fn grpc_endpoint(&self) -> Cow<'static, str> {
29+
crate::path_and_query::<PublishClientEnvelopesRequest>(FILE_DESCRIPTOR_SET)
30+
}
31+
32+
fn body(&self) -> Result<Vec<u8>, BodyError> {
33+
Ok(PublishClientEnvelopesRequest {
34+
envelopes: self.envelopes.clone(),
35+
}
36+
.encode_to_vec())
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use derive_builder::Builder;
2+
use prost::Message;
3+
use std::borrow::Cow;
4+
use xmtp_proto::traits::{BodyError, Endpoint};
5+
use xmtp_proto::xmtp::xmtpv4::message_api::EnvelopesQuery;
6+
use xmtp_proto::xmtp::xmtpv4::message_api::FILE_DESCRIPTOR_SET;
7+
use xmtp_proto::xmtp::xmtpv4::message_api::{QueryEnvelopesRequest, QueryEnvelopesResponse};
8+
9+
/// Query a single thing
10+
#[derive(Debug, Builder, Default, Clone)]
11+
pub struct QueryEnvelope {
12+
#[builder(setter(into))]
13+
topics: Vec<Vec<u8>>,
14+
#[builder(setter(into))]
15+
originator_node_ids: Vec<u32>,
16+
}
17+
18+
impl QueryEnvelope {
19+
pub fn builder() -> QueryEnvelopeBuilder {
20+
Default::default()
21+
}
22+
}
23+
24+
impl Endpoint for QueryEnvelope {
25+
type Output = QueryEnvelopesResponse;
26+
27+
fn http_endpoint(&self) -> Cow<'static, str> {
28+
todo!()
29+
}
30+
31+
fn grpc_endpoint(&self) -> Cow<'static, str> {
32+
crate::path_and_query::<QueryEnvelopesRequest>(FILE_DESCRIPTOR_SET)
33+
}
34+
35+
fn body(&self) -> Result<Vec<u8>, BodyError> {
36+
Ok(QueryEnvelopesRequest {
37+
query: Some(EnvelopesQuery {
38+
topics: self.topics.clone(),
39+
originator_node_ids: self.originator_node_ids.clone(),
40+
last_seen: None,
41+
}),
42+
limit: 1,
43+
}
44+
.encode_to_vec())
45+
}
46+
}
47+
48+
/// Batch Query
49+
#[derive(Debug, Builder, Default)]
50+
#[builder(setter(strip_option))]
51+
pub struct QueryEnvelopes {
52+
#[builder(setter(into))]
53+
envelopes: EnvelopesQuery,
54+
#[builder(setter(into))]
55+
limit: u32,
56+
}
57+
58+
impl QueryEnvelopes {
59+
pub fn builder() -> QueryEnvelopesBuilder {
60+
Default::default()
61+
}
62+
}
63+
64+
impl Endpoint for QueryEnvelopes {
65+
type Output = QueryEnvelopesResponse;
66+
67+
fn http_endpoint(&self) -> Cow<'static, str> {
68+
todo!()
69+
}
70+
71+
fn grpc_endpoint(&self) -> Cow<'static, str> {
72+
crate::path_and_query::<QueryEnvelopesRequest>(FILE_DESCRIPTOR_SET)
73+
}
74+
75+
fn body(&self) -> Result<Vec<u8>, BodyError> {
76+
Ok(QueryEnvelopesRequest {
77+
query: Some(self.envelopes.clone()),
78+
limit: self.limit,
79+
}
80+
.encode_to_vec())
81+
}
82+
}

xmtp_api_d14n/src/endpoints/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod d14n;
2+
pub mod v3;
3+
4+
pub use d14n::*;
5+
pub use v3::*;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use derive_builder::Builder;
2+
use prost::Message;
3+
use std::borrow::Cow;
4+
use xmtp_proto::traits::{BodyError, Endpoint};
5+
use xmtp_proto::xmtp::mls::api::v1::FILE_DESCRIPTOR_SET;
6+
use xmtp_proto::xmtp::mls::api::v1::{FetchKeyPackagesRequest, FetchKeyPackagesResponse};
7+
8+
#[derive(Debug, Builder, Default)]
9+
#[builder(setter(strip_option))]
10+
pub struct FetchKeyPackages {
11+
#[builder(setter(into))]
12+
installation_keys: Vec<Vec<u8>>,
13+
}
14+
15+
impl FetchKeyPackages {
16+
pub fn builder() -> FetchKeyPackagesBuilder {
17+
Default::default()
18+
}
19+
}
20+
21+
impl Endpoint for FetchKeyPackages {
22+
type Output = FetchKeyPackagesResponse;
23+
fn http_endpoint(&self) -> Cow<'static, str> {
24+
todo!()
25+
}
26+
27+
fn grpc_endpoint(&self) -> Cow<'static, str> {
28+
crate::path_and_query::<FetchKeyPackagesRequest>(FILE_DESCRIPTOR_SET)
29+
}
30+
31+
fn body(&self) -> Result<Vec<u8>, BodyError> {
32+
Ok(FetchKeyPackagesRequest {
33+
installation_keys: self.installation_keys.clone(),
34+
}
35+
.encode_to_vec())
36+
}
37+
}
38+
39+
#[cfg(test)]
40+
mod test {
41+
use super::*;
42+
use xmtp_api_grpc::{grpc_client::GrpcClient, LOCALHOST_ADDRESS};
43+
use xmtp_proto::api_client::ApiBuilder;
44+
use xmtp_proto::traits::Query;
45+
46+
#[test]
47+
fn test_file_descriptor() {
48+
let pnq = crate::path_and_query::<FetchKeyPackagesRequest>(FILE_DESCRIPTOR_SET);
49+
println!("{}", pnq);
50+
}
51+
52+
#[tokio::test]
53+
async fn test_fetch_key_packages() {
54+
let mut client = GrpcClient::builder();
55+
client.set_app_version("0.0.0".into()).unwrap();
56+
client.set_tls(false);
57+
client.set_host(LOCALHOST_ADDRESS.to_string());
58+
let client = client.build().await.unwrap();
59+
60+
let endpoint = FetchKeyPackages::builder()
61+
.installation_keys(vec![vec![1, 2, 3]])
62+
.build()
63+
.unwrap();
64+
65+
let result: FetchKeyPackagesResponse = endpoint.query(&client).await.unwrap();
66+
assert_eq!(result.key_packages, vec![]);
67+
}
68+
}

0 commit comments

Comments
 (0)