xmtp_api_d14n/endpoints/d14n/
query_envelopes.rs

1use 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/// Query a single thing
11#[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/// Batch Query
46#[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        // the request will fail b/c we're using dummy data but
126        // we just care if the endpoint is working
127        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}