xmtp_api_d14n/endpoints/d14n/
query_envelopes.rs1use derive_builder::Builder;
2use prost::Message;
3use prost::bytes::Bytes;
4use std::borrow::Cow;
5use xmtp_proto::api::{BodyError, Endpoint};
6use xmtp_proto::types::{GlobalCursor, Topic};
7use xmtp_proto::xmtp::xmtpv4::message_api::QueryEnvelopesRequest;
8use xmtp_proto::xmtp::xmtpv4::message_api::{EnvelopesQuery, QueryEnvelopesResponse};
9
10#[derive(Debug, Builder, Default, Clone)]
12#[builder(build_fn(error = "BodyError"))]
13pub struct QueryEnvelope {
14 #[builder(setter(each(name = "topic", into)))]
15 topics: Vec<Topic>,
16 last_seen: GlobalCursor,
17 limit: u32,
18}
19
20impl QueryEnvelope {
21 pub fn builder() -> QueryEnvelopeBuilder {
22 Default::default()
23 }
24}
25
26impl Endpoint for QueryEnvelope {
27 type Output = QueryEnvelopesResponse;
28 fn grpc_endpoint(&self) -> Cow<'static, str> {
29 xmtp_proto::path_and_query::<QueryEnvelopesRequest>()
30 }
31
32 fn body(&self) -> Result<Bytes, BodyError> {
33 let query = QueryEnvelopesRequest {
34 query: Some(EnvelopesQuery {
35 topics: self.topics.iter().map(Topic::cloned_vec).collect(),
36 originator_node_ids: vec![],
37 last_seen: Some(self.last_seen.clone().into()),
38 }),
39 limit: self.limit,
40 };
41 Ok(query.encode_to_vec().into())
42 }
43}
44
45#[derive(Debug, Builder, Default)]
47#[builder(setter(strip_option), build_fn(error = "BodyError"))]
48pub struct QueryEnvelopes {
49 #[builder(setter(into))]
50 envelopes: EnvelopesQuery,
51 #[builder(setter(into), default)]
52 limit: u32,
53}
54
55impl QueryEnvelopes {
56 pub fn builder() -> QueryEnvelopesBuilder {
57 Default::default()
58 }
59}
60
61impl Endpoint for QueryEnvelopes {
62 type Output = QueryEnvelopesResponse;
63 fn grpc_endpoint(&self) -> Cow<'static, str> {
64 xmtp_proto::path_and_query::<QueryEnvelopesRequest>()
65 }
66
67 fn body(&self) -> Result<Bytes, BodyError> {
68 Ok(QueryEnvelopesRequest {
69 query: Some(self.envelopes.clone()),
70 limit: self.limit,
71 }
72 .encode_to_vec()
73 .into())
74 }
75}
76
77#[cfg(test)]
78mod test {
79 use super::*;
80 use xmtp_api_grpc::{error::GrpcError, test::XmtpdClient};
81 use xmtp_proto::{api, prelude::*, types::TopicKind};
82
83 #[xmtp_common::test]
84 fn test_file_descriptor() {
85 use xmtp_proto::xmtp::xmtpv4::message_api::QueryEnvelopesRequest;
86 let pnq = xmtp_proto::path_and_query::<QueryEnvelopesRequest>();
87 println!("{}", pnq);
88 }
89
90 #[xmtp_common::test]
91 fn test_grpc_endpoint_returns_correct_path() {
92 let endpoint = QueryEnvelopes::default();
93 assert_eq!(
94 endpoint.grpc_endpoint(),
95 "/xmtp.xmtpv4.message_api.ReplicationApi/QueryEnvelopes"
96 );
97 }
98
99 #[xmtp_common::test]
100 fn test_query_envelope_grpc_endpoint_returns_correct_path() {
101 let endpoint = QueryEnvelope::default();
102 assert_eq!(
103 endpoint.grpc_endpoint(),
104 "/xmtp.xmtpv4.message_api.ReplicationApi/QueryEnvelopes"
105 );
106 }
107
108 #[xmtp_common::test]
109 async fn test_query_envelopes() {
110 use crate::d14n::QueryEnvelopes;
111
112 let client = XmtpdClient::create();
113 let client = client.build().unwrap();
114
115 let endpoint = QueryEnvelopes::builder()
116 .envelopes(EnvelopesQuery {
117 topics: vec![vec![]],
118 originator_node_ids: vec![],
119 last_seen: None,
120 })
121 .build()
122 .unwrap();
123 let err = api::ignore(endpoint).query(&client).await.unwrap_err();
124 tracing::info!("{}", err);
125 match err {
128 ApiClientError::<GrpcError>::ClientWithEndpoint {
129 source: GrpcError::Status(ref s),
130 ..
131 } => assert!(s.message().contains("invalid topic"), "{}", err),
132 _ => panic!("request failed"),
133 }
134 }
135
136 #[xmtp_common::test]
137 async fn test_query_envelope() {
138 use crate::d14n::QueryEnvelope;
139
140 let client = XmtpdClient::create();
141 let client = client.build().unwrap();
142
143 let endpoint = QueryEnvelope::builder()
144 .last_seen(Default::default())
145 .topic(TopicKind::GroupMessagesV1.create(vec![]))
146 .limit(0)
147 .build()
148 .unwrap();
149 api::ignore(endpoint).query(&client).await.unwrap();
150 }
151}