1use crate::protocol::EnvelopeCollection;
3
4use crate::protocol::traits::{EnvelopeError, EnvelopeVisitor, Extractor, ProtocolEnvelope};
5use prost::Message;
6use xmtp_proto::identity_v1::get_identity_updates_response::IdentityUpdateLog;
7use xmtp_proto::mls_v1::fetch_key_packages_response::KeyPackage;
8use xmtp_proto::mls_v1::subscribe_group_messages_request::Filter as SubscribeGroupMessagesFilter;
9use xmtp_proto::mls_v1::subscribe_welcome_messages_request::Filter as SubscribeWelcomeMessagesFilter;
10use xmtp_proto::mls_v1::{
11 SubscribeGroupMessagesRequest, SubscribeWelcomeMessagesRequest, welcome_message,
12};
13use xmtp_proto::types::{Cursor, OrphanedEnvelope, Topic};
14use xmtp_proto::xmtp::xmtpv4::message_api::{
15 SubscribeEnvelopesResponse, get_newest_envelope_response,
16};
17use xmtp_proto::{
18 ConversionError,
19 xmtp::identity::{api::v1::get_identity_updates_request, associations::IdentityUpdate},
20 xmtp::mls::api::v1::UploadKeyPackageRequest,
21 xmtp::mls::api::v1::{
22 GroupMessage as V3ProtoGroupMessage, GroupMessageInput,
23 WelcomeMessage as V3ProtoWelcomeMessage, WelcomeMessageInput, group_message,
24 group_message_input::Version as GroupMessageVersion,
25 welcome_message_input::Version as WelcomeMessageVersion,
26 },
27 xmtp::xmtpv4::envelopes::client_envelope::Payload,
28 xmtp::xmtpv4::envelopes::{
29 ClientEnvelope, OriginatorEnvelope, PayerEnvelope, UnsignedOriginatorEnvelope,
30 },
31};
32
33impl<'env> ProtocolEnvelope<'env> for OriginatorEnvelope {
34 type Nested<'a> = UnsignedOriginatorEnvelope;
35
36 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
37 where
38 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
39 {
40 visitor.visit_originator(self)?;
41 let unsigned = self.get_nested()?;
42 unsigned.accept(visitor)?;
43 Ok(())
44 }
45
46 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
47 Ok(UnsignedOriginatorEnvelope::decode(
48 self.unsigned_originator_envelope.as_slice(),
49 )?)
50 }
51}
52
53impl<'env> ProtocolEnvelope<'env> for UnsignedOriginatorEnvelope {
54 type Nested<'a> = PayerEnvelope;
55 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
56 where
57 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
58 {
59 visitor.visit_unsigned_originator(self)?;
60 let payer = self.get_nested()?;
61 payer.accept(visitor)?;
62 Ok(())
63 }
64
65 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
66 Ok(PayerEnvelope::decode(self.payer_envelope_bytes.as_slice())?)
67 }
68}
69
70impl<'env> ProtocolEnvelope<'env> for PayerEnvelope {
71 type Nested<'a> = ClientEnvelope;
72
73 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
74 where
75 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
76 {
77 visitor.visit_payer(self)?;
78 let client = self.get_nested()?;
79 client.accept(visitor)?;
80 Ok(())
81 }
82
83 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
84 Ok(ClientEnvelope::decode(
85 self.unsigned_client_envelope.as_slice(),
86 )?)
87 }
88}
89
90impl<'env> ProtocolEnvelope<'env>
91 for xmtp_proto::mls_v1::get_newest_group_message_response::Response
92{
93 type Nested<'a> = ();
94
95 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
96 where
97 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
98 {
99 visitor.visit_newest_group_message_response(self)?;
100 Ok(())
101 }
102
103 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
104 Ok(())
105 }
106}
107
108impl<'env> ProtocolEnvelope<'env> for ClientEnvelope {
109 type Nested<'a> = Option<&'a Payload>;
110
111 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
112 where
113 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
114 {
115 visitor.visit_client(self)?;
116 self.get_nested()?.accept(visitor)?;
117 Ok(())
118 }
119
120 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
121 Ok(self.payload.as_ref())
124 }
125}
126
127impl<'env> ProtocolEnvelope<'env> for Payload {
128 type Nested<'a> = ();
129
130 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
131 where
132 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
133 {
134 match self {
135 Payload::GroupMessage(msg) => msg.accept(visitor)?,
136 Payload::WelcomeMessage(msg) => msg.accept(visitor)?,
137 Payload::UploadKeyPackage(msg) => msg.accept(visitor)?,
138 Payload::IdentityUpdate(msg) => msg.accept(visitor)?,
139 Payload::PayerReport(_) => {
140 tracing::warn!("Payload::PayerReport type not handled in client");
141 return Ok(());
142 }
143 Payload::PayerReportAttestation(_) => {
144 tracing::warn!("Payload::PayerReportAttestation type not handled in client");
145 return Ok(());
146 }
147 };
148 Ok(())
149 }
150
151 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
152 Ok(())
153 }
154}
155
156impl<'env> ProtocolEnvelope<'env> for GroupMessageInput {
157 type Nested<'a> = Option<&'a GroupMessageVersion>;
158
159 fn accept<'a, V: EnvelopeVisitor<'env>>(&'a self, visitor: &mut V) -> Result<(), EnvelopeError>
160 where
161 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
162 {
163 visitor.visit_group_message_input(self)?;
164 if let Some(versioned) = self.get_nested()? {
165 versioned.accept(visitor)?;
166 }
167 Ok(())
168 }
169
170 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
171 Ok(self.version.as_ref())
174 }
175}
176
177impl<'env> ProtocolEnvelope<'env> for GroupMessageVersion {
180 type Nested<'a> = ();
181
182 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
183 where
184 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
185 {
186 visitor.visit_group_message_version(self)?;
187 match self {
188 GroupMessageVersion::V1(v1) => visitor.visit_group_message_v1(v1),
189 }?;
190 Ok(())
191 }
192
193 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
194 Ok(())
195 }
196}
197
198impl<'env> ProtocolEnvelope<'env> for WelcomeMessageInput {
199 type Nested<'a> = Option<&'a WelcomeMessageVersion>;
200
201 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
202 where
203 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
204 {
205 visitor.visit_welcome_message_input(self)?;
206 self.get_nested()?.accept(visitor)?;
207 Ok(())
208 }
209
210 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
211 Ok(self.version.as_ref())
214 }
215}
216
217impl<'env> ProtocolEnvelope<'env> for WelcomeMessageVersion {
218 type Nested<'a> = ();
219
220 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
221 where
222 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
223 {
224 visitor.visit_welcome_message_version(self)?;
225 match self {
226 WelcomeMessageVersion::V1(v1) => visitor.visit_welcome_message_v1(v1)?,
227 WelcomeMessageVersion::WelcomePointer(wp) => visitor.visit_welcome_pointer(wp)?,
228 }
229 Ok(())
230 }
231
232 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
233 Ok(())
234 }
235}
236
237impl<'env> ProtocolEnvelope<'env> for UploadKeyPackageRequest {
238 type Nested<'a> = ();
239
240 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
241 where
242 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
243 {
244 visitor.visit_upload_key_package(self)?;
245 self.get_nested()?.accept(visitor)?;
246 Ok(())
247 }
248
249 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
250 Ok(())
251 }
252}
253
254impl<'env> ProtocolEnvelope<'env> for IdentityUpdate {
255 type Nested<'a> = ();
256
257 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
258 where
259 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
260 {
261 visitor.visit_identity_update(self)?;
262 self.get_nested()?.accept(visitor)?;
263 Ok(())
264 }
265
266 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
267 Ok(())
268 }
269}
270
271impl<'env> ProtocolEnvelope<'env> for get_identity_updates_request::Request {
272 type Nested<'a> = ();
273
274 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
275 where
276 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
277 {
278 visitor.visit_identity_updates_request(self)?;
279 self.get_nested()?.accept(visitor)?;
280 Ok(())
281 }
282
283 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
284 Ok(())
285 }
286}
287
288impl<'env> ProtocolEnvelope<'env> for KeyPackage {
289 type Nested<'a> = ();
290
291 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
292 where
293 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
294 {
295 visitor.visit_key_package(self)?;
296 self.get_nested()?.accept(visitor)?;
297 Ok(())
298 }
299
300 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
301 Ok(())
302 }
303}
304
305impl<'env> ProtocolEnvelope<'env> for get_newest_envelope_response::Response {
306 type Nested<'a> = Option<&'a OriginatorEnvelope>;
307
308 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
309 where
310 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
311 {
312 visitor.visit_newest_envelope_response(self)?;
313 self.get_nested()?.accept(visitor)?;
314 Ok(())
315 }
316
317 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
318 Ok(self.originator_envelope.as_ref())
319 }
320}
321
322impl<'env, T> ProtocolEnvelope<'env> for Option<&T>
323where
324 T: ProtocolEnvelope<'env>,
325{
326 type Nested<'a>
327 = ()
328 where
329 Self: 'a;
330
331 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
332 where
333 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
334 {
335 match self {
336 Some(o) => o.accept(visitor),
337 None => Ok(visitor.visit_none()?),
338 }
339 }
340
341 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
342 Ok(())
343 }
344}
345
346impl<'env> ProtocolEnvelope<'env> for SubscribeGroupMessagesFilter {
347 type Nested<'a> = ();
348
349 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
350 where
351 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
352 {
353 visitor.visit_subscribe_group_messages_request(self)?;
354 Ok(())
355 }
356
357 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
358 Ok(())
359 }
360}
361
362impl<'env> ProtocolEnvelope<'env> for SubscribeWelcomeMessagesFilter {
363 type Nested<'a> = ();
364
365 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
366 where
367 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
368 {
369 visitor.visit_subscribe_welcome_messages_request(self)?;
370 Ok(())
371 }
372
373 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
374 Ok(())
375 }
376}
377
378impl<'env> ProtocolEnvelope<'env> for V3ProtoGroupMessage {
379 type Nested<'a> = Option<&'a group_message::Version>;
380
381 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
382 where
383 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
384 {
385 self.get_nested()?.accept(visitor)
386 }
387
388 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
389 Ok(self.version.as_ref())
390 }
391}
392
393impl<'env> ProtocolEnvelope<'env> for group_message::Version {
394 type Nested<'a> = ();
395
396 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
397 where
398 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
399 {
400 match self {
401 group_message::Version::V1(v1) => visitor.visit_v3_group_message(v1)?,
402 }
403 Ok(())
404 }
405
406 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
407 Ok(())
408 }
409}
410
411impl<'env> ProtocolEnvelope<'env> for V3ProtoWelcomeMessage {
412 type Nested<'a> = Option<&'a welcome_message::Version>;
413
414 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
415 where
416 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
417 {
418 self.get_nested()?.accept(visitor)
419 }
420
421 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
422 Ok(self.version.as_ref())
423 }
424}
425
426impl<'env> ProtocolEnvelope<'env> for welcome_message::Version {
427 type Nested<'a> = ();
428
429 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
430 where
431 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
432 {
433 match self {
434 welcome_message::Version::V1(v1) => visitor.visit_v3_welcome_message(v1)?,
435 welcome_message::Version::WelcomePointer(wp) => visitor.visit_v3_welcome_pointer(wp)?,
436 }
437 Ok(())
438 }
439
440 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
441 Ok(())
442 }
443}
444
445impl<'env> ProtocolEnvelope<'env> for IdentityUpdateLog {
446 type Nested<'a> = Option<&'a IdentityUpdate>;
447
448 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
449 where
450 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
451 {
452 visitor.visit_identity_update_log(self)?;
453 self.get_nested()?.accept(visitor)
454 }
455
456 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
457 Ok(self.update.as_ref())
458 }
459}
460
461impl<'env> ProtocolEnvelope<'env> for () {
462 type Nested<'a> = ();
463
464 fn accept<V: EnvelopeVisitor<'env>>(&self, _: &mut V) -> Result<(), EnvelopeError>
465 where
466 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
467 {
468 Ok(())
469 }
470
471 fn get_nested(&self) -> Result<Self::Nested<'_>, ConversionError> {
472 Ok(())
473 }
474}
475
476impl EnvelopeCollection<'_> for SubscribeEnvelopesResponse {
477 fn topics(&self) -> Result<Vec<Topic>, EnvelopeError> {
478 self.envelopes.topics()
479 }
480
481 fn cursors(&self) -> Result<Vec<Cursor>, EnvelopeError> {
482 self.envelopes.cursors()
483 }
484
485 fn payloads(&self) -> Result<Vec<Payload>, EnvelopeError> {
486 self.envelopes.payloads()
487 }
488
489 fn sha256_hashes(&self) -> Result<Vec<Vec<u8>>, EnvelopeError> {
490 self.envelopes.sha256_hashes()
491 }
492
493 fn client_envelopes(&self) -> Result<Vec<ClientEnvelope>, EnvelopeError> {
494 self.envelopes.client_envelopes()
495 }
496
497 fn len(&self) -> usize {
498 self.envelopes.len()
499 }
500
501 fn is_empty(&self) -> bool {
502 self.envelopes.is_empty()
503 }
504
505 fn consume<E>(self) -> Result<Vec<<E as Extractor>::Output>, EnvelopeError>
506 where
507 for<'a> E: Default + Extractor + EnvelopeVisitor<'a>,
508 Self: Clone,
509 for<'a> EnvelopeError: From<<E as EnvelopeVisitor<'a>>::Error>,
510 Self: Sized,
511 {
512 self.envelopes.consume::<E>()
513 }
514
515 fn group_messages(
516 &self,
517 ) -> Result<Vec<Option<xmtp_proto::types::GroupMessage>>, EnvelopeError> {
518 self.envelopes.group_messages()
519 }
520
521 fn welcome_messages(
522 &self,
523 ) -> Result<Vec<Option<xmtp_proto::types::WelcomeMessage>>, EnvelopeError> {
524 self.envelopes.welcome_messages()
525 }
526
527 fn orphans(&self) -> Result<Vec<OrphanedEnvelope>, EnvelopeError> {
528 self.envelopes.orphans()
529 }
530}
531
532impl EnvelopeCollection<'_> for SubscribeGroupMessagesRequest {
533 fn topics(&self) -> Result<Vec<Topic>, EnvelopeError> {
534 self.filters.topics()
535 }
536
537 fn cursors(&self) -> Result<Vec<Cursor>, EnvelopeError> {
538 self.filters.cursors()
539 }
540
541 fn payloads(&self) -> Result<Vec<Payload>, EnvelopeError> {
542 self.filters.payloads()
543 }
544
545 fn sha256_hashes(&self) -> Result<Vec<Vec<u8>>, EnvelopeError> {
546 self.filters.sha256_hashes()
547 }
548
549 fn client_envelopes(&self) -> Result<Vec<ClientEnvelope>, EnvelopeError> {
550 self.filters.client_envelopes()
551 }
552
553 fn len(&self) -> usize {
554 self.filters.len()
555 }
556
557 fn is_empty(&self) -> bool {
558 self.filters.is_empty()
559 }
560
561 fn consume<E>(self) -> Result<Vec<<E as Extractor>::Output>, EnvelopeError>
562 where
563 for<'a> E: Default + Extractor + EnvelopeVisitor<'a>,
564 for<'a> EnvelopeError: From<<E as EnvelopeVisitor<'a>>::Error>,
565 Self: Sized,
566 {
567 self.filters.consume()
568 }
569
570 fn group_messages(
571 &self,
572 ) -> Result<Vec<Option<xmtp_proto::types::GroupMessage>>, EnvelopeError> {
573 self.filters.group_messages()
574 }
575
576 fn welcome_messages(
577 &self,
578 ) -> Result<Vec<Option<xmtp_proto::types::WelcomeMessage>>, EnvelopeError> {
579 self.filters.welcome_messages()
580 }
581
582 fn orphans(&self) -> Result<Vec<OrphanedEnvelope>, EnvelopeError> {
583 self.filters.orphans()
584 }
585}
586
587impl EnvelopeCollection<'_> for SubscribeWelcomeMessagesRequest {
588 fn topics(&self) -> Result<Vec<Topic>, EnvelopeError> {
589 self.filters.topics()
590 }
591
592 fn cursors(&self) -> Result<Vec<Cursor>, EnvelopeError> {
593 self.filters.cursors()
594 }
595
596 fn payloads(&self) -> Result<Vec<Payload>, EnvelopeError> {
597 self.filters.payloads()
598 }
599
600 fn sha256_hashes(&self) -> Result<Vec<Vec<u8>>, EnvelopeError> {
601 self.filters.sha256_hashes()
602 }
603
604 fn client_envelopes(&self) -> Result<Vec<ClientEnvelope>, EnvelopeError> {
605 self.filters.client_envelopes()
606 }
607
608 fn len(&self) -> usize {
609 self.filters.len()
610 }
611
612 fn is_empty(&self) -> bool {
613 self.filters.is_empty()
614 }
615
616 fn consume<E>(self) -> Result<Vec<<E as Extractor>::Output>, EnvelopeError>
617 where
618 for<'a> E: Default + Extractor + EnvelopeVisitor<'a>,
619 for<'a> EnvelopeError: From<<E as EnvelopeVisitor<'a>>::Error>,
620 Self: Sized,
621 {
622 self.filters.consume()
623 }
624
625 fn group_messages(
626 &self,
627 ) -> Result<Vec<Option<xmtp_proto::types::GroupMessage>>, EnvelopeError> {
628 self.filters.group_messages()
629 }
630
631 fn welcome_messages(
632 &self,
633 ) -> Result<Vec<Option<xmtp_proto::types::WelcomeMessage>>, EnvelopeError> {
634 self.filters.welcome_messages()
635 }
636
637 fn orphans(&self) -> Result<Vec<OrphanedEnvelope>, EnvelopeError> {
638 self.filters.orphans()
639 }
640}
641
642#[cfg(any(test, feature = "test-utils"))]
643impl<'env> ProtocolEnvelope<'env> for u32 {
644 type Nested<'a> = ();
645
646 fn accept<V: EnvelopeVisitor<'env>>(&self, visitor: &mut V) -> Result<(), EnvelopeError>
647 where
648 EnvelopeError: From<<V as EnvelopeVisitor<'env>>::Error>,
649 {
650 visitor.test_visit_u32(self)?;
651 Ok(())
652 }
653
654 fn get_nested(&self) -> Result<Self::Nested<'_>, xmtp_proto::ConversionError> {
655 Ok(())
656 }
657}
658
659#[cfg(test)]
660mod tests {
661 use super::*;
662 use crate::protocol::Envelope;
663 use crate::protocol::extractors::test_utils::*;
664 use rstest::rstest;
665 use xmtp_common::Generate;
666 use xmtp_cryptography::XmtpInstallationCredential;
667 use xmtp_proto::types::TopicKind;
668 use xmtp_proto::xmtp::mls::api::v1::{
669 GroupMessage as V3ProtoGroupMessage, WelcomeMessage as V3ProtoWelcomeMessage,
670 group_message, group_message_input::V1 as GroupMessageV1, welcome_message,
671 welcome_message_input::V1 as WelcomeMessageV1,
672 };
673 use xmtp_proto::xmtp::xmtpv4::envelopes::AuthenticatedData;
674
675 #[derive(Default, Debug)]
677 struct TestVisitor {
678 visited_originator: bool,
679 visited_client: bool,
680 visited_group_message_v1: bool,
681 visited_welcome_message_v1: bool,
682 visited_upload_key_package: bool,
683 visited_identity_update: bool,
684 visited_none: bool,
685 visited_v3_group_message: bool,
686 visited_v3_welcome_message: bool,
687 }
688
689 impl<'env> EnvelopeVisitor<'env> for TestVisitor {
690 type Error = super::EnvelopeError;
691
692 fn visit_originator(&mut self, _e: &OriginatorEnvelope) -> Result<(), Self::Error> {
693 self.visited_originator = true;
694 Ok(())
695 }
696
697 fn visit_client(&mut self, _e: &ClientEnvelope) -> Result<(), Self::Error> {
698 self.visited_client = true;
699 Ok(())
700 }
701
702 fn visit_group_message_v1(&mut self, _m: &GroupMessageV1) -> Result<(), Self::Error> {
703 self.visited_group_message_v1 = true;
704 Ok(())
705 }
706
707 fn visit_welcome_message_v1(&mut self, _m: &WelcomeMessageV1) -> Result<(), Self::Error> {
708 self.visited_welcome_message_v1 = true;
709 Ok(())
710 }
711
712 fn visit_upload_key_package(
713 &mut self,
714 _p: &UploadKeyPackageRequest,
715 ) -> Result<(), Self::Error> {
716 self.visited_upload_key_package = true;
717 Ok(())
718 }
719
720 fn visit_identity_update(&mut self, _u: &IdentityUpdate) -> Result<(), Self::Error> {
721 self.visited_identity_update = true;
722 Ok(())
723 }
724
725 fn visit_none(&mut self) -> Result<(), Self::Error> {
726 self.visited_none = true;
727 Ok(())
728 }
729
730 fn visit_v3_group_message(&mut self, _m: &group_message::V1) -> Result<(), Self::Error> {
731 self.visited_v3_group_message = true;
732 Ok(())
733 }
734
735 fn visit_v3_welcome_message(
736 &mut self,
737 _m: &welcome_message::V1,
738 ) -> Result<(), Self::Error> {
739 self.visited_v3_welcome_message = true;
740 Ok(())
741 }
742 }
743
744 #[rstest]
745 #[case::group_message(
746 |builder: TestEnvelopeBuilder| builder.with_application_message(vec![1,2,3]),
747 |visitor: &TestVisitor| visitor.visited_group_message_v1,
748 )]
749 #[case::welcome_message(
750 |builder: TestEnvelopeBuilder| builder.with_welcome_message(vec![1,2,3,4]),
751 |visitor: &TestVisitor| visitor.visited_welcome_message_v1,
752 )]
753 #[case::key_package(
754 |builder: TestEnvelopeBuilder| builder.with_key_package("test".to_string(), XmtpInstallationCredential::default()),
755 |visitor: &TestVisitor| visitor.visited_upload_key_package,
756 )]
757 #[case::identity_update(
758 |builder: TestEnvelopeBuilder| builder.with_identity_update(),
759 |visitor: &TestVisitor| visitor.visited_identity_update,
760 )]
761 #[xmtp_common::test]
762 async fn envelope_visitor_flows<F, P>(#[case] envelope_builder: F, #[case] payload_check: P)
763 where
764 F: Fn(TestEnvelopeBuilder) -> TestEnvelopeBuilder,
765 P: Fn(&TestVisitor) -> bool,
766 {
767 let envelope = envelope_builder(TestEnvelopeBuilder::new()).build();
768 let mut visitor = TestVisitor::default();
769 envelope.accept(&mut visitor).unwrap();
770
771 assert!(visitor.visited_originator, "originator should be visited");
773 assert!(visitor.visited_client, "client should be visited");
774
775 assert!(
777 payload_check(&visitor),
778 "payload-specific visitor should be called"
779 );
780
781 assert!(envelope.topic().is_ok(), "topic extraction should work");
783 assert!(envelope.payload().is_ok(), "payload extraction should work");
784 assert!(
785 envelope.client_envelope().is_ok(),
786 "client envelope extraction should work"
787 );
788 }
789
790 #[xmtp_common::test]
791 fn envelope_collections() {
792 let envelopes = vec![
793 TestEnvelopeBuilder::new()
794 .with_application_message(vec![1, 2, 3])
795 .build(),
796 TestEnvelopeBuilder::new()
797 .with_welcome_message(vec![4, 5, 6, 7])
798 .build(),
799 TestEnvelopeBuilder::new()
800 .with_key_package("test".to_string(), XmtpInstallationCredential::default())
801 .build(),
802 TestEnvelopeBuilder::new().with_identity_update().build(),
803 ];
804 let response = SubscribeEnvelopesResponse {
806 envelopes: envelopes.clone(),
807 };
808 assert_eq!(response.len(), 4);
809 assert_eq!(response.payloads().unwrap().len(), 4);
810 assert_eq!(response.client_envelopes().unwrap().len(), 4);
811 assert!(!response.is_empty());
812
813 let empty_response = SubscribeEnvelopesResponse { envelopes: vec![] };
814 assert_eq!(empty_response.len(), 0);
815 assert!(empty_response.is_empty());
816 }
817
818 #[xmtp_common::test]
819 fn envelope_error_handling() {
820 let mut envelope = TestEnvelopeBuilder::new()
822 .with_application_message(vec![1, 2, 3])
823 .build();
824 envelope.unsigned_originator_envelope = vec![0xFF];
825 assert!(envelope.get_nested().is_err());
826
827 let unsigned = UnsignedOriginatorEnvelope {
829 originator_node_id: 1,
830 originator_sequence_id: 1,
831 originator_ns: 1000,
832 payer_envelope_bytes: vec![0xFF, 0xFF, 0xFF],
833 base_fee_picodollars: 0,
834 congestion_fee_picodollars: 0,
835 expiry_unixtime: 0,
836 };
837 assert!(unsigned.get_nested().is_err());
838
839 let payer = PayerEnvelope {
841 unsigned_client_envelope: vec![0xFF, 0xFF, 0xFF],
842 payer_signature: None,
843 target_originator: 0,
844 message_retention_days: 30,
845 };
846 assert!(payer.get_nested().is_err());
847 }
848
849 #[xmtp_common::test]
850 fn envelope_edge_cases() {
851 let client = ClientEnvelope {
853 aad: Some(AuthenticatedData::with_topic(
854 TopicKind::IdentityUpdatesV1.create([0, 1, 2]),
855 )),
856 payload: None,
857 };
858 let mut visitor = TestVisitor::default();
859 client.accept(&mut visitor).unwrap();
860 assert!(visitor.visited_client && visitor.visited_none);
861
862 let envelope = TestEnvelopeBuilder::new()
864 .with_application_message(vec![1, 2, 3])
865 .build();
866 let some_envelope = Some(&envelope);
867 let none_envelope: Option<&OriginatorEnvelope> = None;
868
869 let mut visitor = TestVisitor::default();
870 some_envelope.accept(&mut visitor).unwrap();
871 assert!(visitor.visited_originator && !visitor.visited_none);
872
873 let mut visitor = TestVisitor::default();
874 none_envelope.accept(&mut visitor).unwrap();
875 assert!(visitor.visited_none && !visitor.visited_originator);
876 }
877
878 #[xmtp_common::test]
879 fn test_v3_message_visitors() {
880 macro_rules! test_case {
881 ($msg:expr, $expected:expr, $field:ident) => {{
882 let mut visitor = TestVisitor::default();
883 $msg.accept(&mut visitor).unwrap();
884 assert_eq!(
885 visitor.$field,
886 $expected,
887 "V3 {} should be {}",
888 stringify!($field),
889 $expected
890 );
891 }};
892 }
893
894 test_case!(
896 V3ProtoGroupMessage {
897 version: Some(group_message::Version::V1(group_message::V1::generate()))
898 },
899 true,
900 visited_v3_group_message
901 );
902 test_case!(
903 V3ProtoGroupMessage { version: None },
904 false,
905 visited_v3_group_message
906 );
907 test_case!(
908 V3ProtoWelcomeMessage {
909 version: Some(welcome_message::Version::V1(welcome_message::V1::generate()))
910 },
911 true,
912 visited_v3_welcome_message
913 );
914 test_case!(
915 V3ProtoWelcomeMessage { version: None },
916 false,
917 visited_v3_welcome_message
918 );
919 test_case!(
920 group_message::Version::V1(group_message::V1::generate()),
921 true,
922 visited_v3_group_message
923 );
924 test_case!(
925 welcome_message::Version::V1(welcome_message::V1::generate()),
926 true,
927 visited_v3_welcome_message
928 );
929 }
930}