@@ -7,6 +7,7 @@ use tokio::sync::Mutex;
7
7
use xmtp_api:: { strategies, ApiClientWrapper } ;
8
8
use xmtp_api_grpc:: grpc_api_helper:: Client as TonicApiClient ;
9
9
use xmtp_common:: { AbortHandle , GenericStreamHandle , StreamHandle } ;
10
+ use xmtp_content_types:: multi_remote_attachment:: MultiRemoteAttachmentCodec ;
10
11
use xmtp_content_types:: reaction:: ReactionCodec ;
11
12
use xmtp_content_types:: ContentCodec ;
12
13
use xmtp_id:: associations:: { verify_signed_with_public_context, DeserializationError } ;
@@ -54,7 +55,9 @@ use xmtp_mls::{
54
55
} ;
55
56
use xmtp_proto:: api_client:: ApiBuilder ;
56
57
use xmtp_proto:: xmtp:: device_sync:: BackupElementSelection ;
57
- use xmtp_proto:: xmtp:: mls:: message_contents:: content_types:: ReactionV2 ;
58
+ use xmtp_proto:: xmtp:: mls:: message_contents:: content_types:: {
59
+ MultiRemoteAttachment , ReactionV2 , RemoteAttachmentInfo ,
60
+ } ;
58
61
use xmtp_proto:: xmtp:: mls:: message_contents:: { DeviceSyncKind , EncodedContent } ;
59
62
pub type RustXmtpClient = MlsClient < TonicApiClient > ;
60
63
@@ -2228,6 +2231,111 @@ impl From<FfiReactionSchema> for i32 {
2228
2231
}
2229
2232
}
2230
2233
2234
+ #[ derive( uniffi:: Record , Clone , Default ) ]
2235
+ pub struct FfiRemoteAttachmentInfo {
2236
+ pub secret : Vec < u8 > ,
2237
+ pub content_digest : String ,
2238
+ pub nonce : Vec < u8 > ,
2239
+ pub scheme : String ,
2240
+ pub url : String ,
2241
+ pub salt : Vec < u8 > ,
2242
+ pub content_length : Option < u32 > ,
2243
+ pub filename : Option < String > ,
2244
+ }
2245
+
2246
+ impl From < FfiRemoteAttachmentInfo > for RemoteAttachmentInfo {
2247
+ fn from ( ffi_remote_attachment_info : FfiRemoteAttachmentInfo ) -> Self {
2248
+ RemoteAttachmentInfo {
2249
+ content_digest : ffi_remote_attachment_info. content_digest ,
2250
+ secret : ffi_remote_attachment_info. secret ,
2251
+ nonce : ffi_remote_attachment_info. nonce ,
2252
+ salt : ffi_remote_attachment_info. salt ,
2253
+ scheme : ffi_remote_attachment_info. scheme ,
2254
+ url : ffi_remote_attachment_info. url ,
2255
+ content_length : ffi_remote_attachment_info. content_length ,
2256
+ filename : ffi_remote_attachment_info. filename ,
2257
+ }
2258
+ }
2259
+ }
2260
+
2261
+ impl From < RemoteAttachmentInfo > for FfiRemoteAttachmentInfo {
2262
+ fn from ( remote_attachment_info : RemoteAttachmentInfo ) -> Self {
2263
+ FfiRemoteAttachmentInfo {
2264
+ secret : remote_attachment_info. secret ,
2265
+ content_digest : remote_attachment_info. content_digest ,
2266
+ nonce : remote_attachment_info. nonce ,
2267
+ scheme : remote_attachment_info. scheme ,
2268
+ url : remote_attachment_info. url ,
2269
+ salt : remote_attachment_info. salt ,
2270
+ content_length : remote_attachment_info. content_length ,
2271
+ filename : remote_attachment_info. filename ,
2272
+ }
2273
+ }
2274
+ }
2275
+
2276
+ #[ derive( uniffi:: Record , Clone , Default ) ]
2277
+ pub struct FfiMultiRemoteAttachment {
2278
+ pub attachments : Vec < FfiRemoteAttachmentInfo > ,
2279
+ }
2280
+
2281
+ impl From < FfiMultiRemoteAttachment > for MultiRemoteAttachment {
2282
+ fn from ( ffi_multi_remote_attachment : FfiMultiRemoteAttachment ) -> Self {
2283
+ MultiRemoteAttachment {
2284
+ attachments : ffi_multi_remote_attachment
2285
+ . attachments
2286
+ . into_iter ( )
2287
+ . map ( Into :: into)
2288
+ . collect ( ) ,
2289
+ }
2290
+ }
2291
+ }
2292
+
2293
+ impl From < MultiRemoteAttachment > for FfiMultiRemoteAttachment {
2294
+ fn from ( multi_remote_attachment : MultiRemoteAttachment ) -> Self {
2295
+ FfiMultiRemoteAttachment {
2296
+ attachments : multi_remote_attachment
2297
+ . attachments
2298
+ . into_iter ( )
2299
+ . map ( Into :: into)
2300
+ . collect ( ) ,
2301
+ }
2302
+ }
2303
+ }
2304
+
2305
+ #[ uniffi:: export]
2306
+ pub fn encode_multi_remote_attachment (
2307
+ ffi_multi_remote_attachment : FfiMultiRemoteAttachment ,
2308
+ ) -> Result < Vec < u8 > , GenericError > {
2309
+ // Convert FfiMultiRemoteAttachment to MultiRemoteAttachment
2310
+ let multi_remote_attachment: MultiRemoteAttachment = ffi_multi_remote_attachment. into ( ) ;
2311
+
2312
+ // Use MultiRemoteAttachmentCodec to encode the reaction
2313
+ let encoded = MultiRemoteAttachmentCodec :: encode ( multi_remote_attachment)
2314
+ . map_err ( |e| GenericError :: Generic { err : e. to_string ( ) } ) ?;
2315
+
2316
+ // Encode the EncodedContent to bytes
2317
+ let mut buf = Vec :: new ( ) ;
2318
+ encoded
2319
+ . encode ( & mut buf)
2320
+ . map_err ( |e| GenericError :: Generic { err : e. to_string ( ) } ) ?;
2321
+
2322
+ Ok ( buf)
2323
+ }
2324
+
2325
+ #[ uniffi:: export]
2326
+ pub fn decode_multi_remote_attachment (
2327
+ bytes : Vec < u8 > ,
2328
+ ) -> Result < FfiMultiRemoteAttachment , GenericError > {
2329
+ // Decode bytes into EncodedContent
2330
+ let encoded_content = EncodedContent :: decode ( bytes. as_slice ( ) )
2331
+ . map_err ( |e| GenericError :: Generic { err : e. to_string ( ) } ) ?;
2332
+
2333
+ // Use MultiRemoteAttachmentCodec to decode into MultiRemoteAttachment and convert to FfiMultiRemoteAttachment
2334
+ MultiRemoteAttachmentCodec :: decode ( encoded_content)
2335
+ . map ( Into :: into)
2336
+ . map_err ( |e| GenericError :: Generic { err : e. to_string ( ) } )
2337
+ }
2338
+
2231
2339
#[ derive( uniffi:: Record , Clone ) ]
2232
2340
pub struct FfiMessage {
2233
2341
pub id : Vec < u8 > ,
@@ -2436,14 +2544,16 @@ mod tests {
2436
2544
FfiPreferenceUpdate , FfiXmtpClient ,
2437
2545
} ;
2438
2546
use crate :: {
2439
- connect_to_backend, decode_reaction, encode_reaction, get_inbox_id_for_address,
2547
+ connect_to_backend, decode_multi_remote_attachment, decode_reaction,
2548
+ encode_multi_remote_attachment, encode_reaction, get_inbox_id_for_address,
2440
2549
inbox_owner:: SigningError , FfiConsent , FfiConsentEntityType , FfiConsentState ,
2441
2550
FfiContentType , FfiConversation , FfiConversationCallback , FfiConversationMessageKind ,
2442
2551
FfiCreateDMOptions , FfiCreateGroupOptions , FfiDirection , FfiGroupPermissionsOptions ,
2443
2552
FfiInboxOwner , FfiListConversationsOptions , FfiListMessagesOptions ,
2444
2553
FfiMessageDisappearingSettings , FfiMessageWithReactions , FfiMetadataField ,
2445
- FfiPermissionPolicy , FfiPermissionPolicySet , FfiPermissionUpdateType , FfiReaction ,
2446
- FfiReactionAction , FfiReactionSchema , FfiSubscribeError ,
2554
+ FfiMultiRemoteAttachment , FfiPermissionPolicy , FfiPermissionPolicySet ,
2555
+ FfiPermissionUpdateType , FfiReaction , FfiReactionAction , FfiReactionSchema ,
2556
+ FfiRemoteAttachmentInfo , FfiSubscribeError ,
2447
2557
} ;
2448
2558
use ethers:: utils:: hex;
2449
2559
use prost:: Message ;
@@ -6857,4 +6967,58 @@ mod tests {
6857
6967
// Clean up stream
6858
6968
stream. end_and_wait ( ) . await . unwrap ( ) ;
6859
6969
}
6970
+
6971
+ #[ tokio:: test]
6972
+ async fn test_multi_remote_attachment_encode_decode ( ) {
6973
+ // Create a test attachment
6974
+ let original_attachment = FfiMultiRemoteAttachment {
6975
+ attachments : vec ! [
6976
+ FfiRemoteAttachmentInfo {
6977
+ filename: Some ( "test1.jpg" . to_string( ) ) ,
6978
+ content_length: Some ( 1000 ) ,
6979
+ secret: vec![ 1 , 2 , 3 ] ,
6980
+ content_digest: "123" . to_string( ) ,
6981
+ nonce: vec![ 7 , 8 , 9 ] ,
6982
+ salt: vec![ 1 , 2 , 3 ] ,
6983
+ scheme: "https" . to_string( ) ,
6984
+ url: "https://example.com/test1.jpg" . to_string( ) ,
6985
+ } ,
6986
+ FfiRemoteAttachmentInfo {
6987
+ filename: Some ( "test2.pdf" . to_string( ) ) ,
6988
+ content_length: Some ( 2000 ) ,
6989
+ secret: vec![ 4 , 5 , 6 ] ,
6990
+ content_digest: "456" . to_string( ) ,
6991
+ nonce: vec![ 10 , 11 , 12 ] ,
6992
+ salt: vec![ 1 , 2 , 3 ] ,
6993
+ scheme: "https" . to_string( ) ,
6994
+ url: "https://example.com/test2.pdf" . to_string( ) ,
6995
+ } ,
6996
+ ] ,
6997
+ } ;
6998
+
6999
+ // Encode the attachment
7000
+ let encoded_bytes = encode_multi_remote_attachment ( original_attachment. clone ( ) )
7001
+ . expect ( "Should encode multi remote attachment successfully" ) ;
7002
+
7003
+ // Decode the attachment
7004
+ let decoded_attachment = decode_multi_remote_attachment ( encoded_bytes)
7005
+ . expect ( "Should decode multi remote attachment successfully" ) ;
7006
+
7007
+ assert_eq ! (
7008
+ decoded_attachment. attachments. len( ) ,
7009
+ original_attachment. attachments. len( )
7010
+ ) ;
7011
+
7012
+ for ( decoded, original) in decoded_attachment
7013
+ . attachments
7014
+ . iter ( )
7015
+ . zip ( original_attachment. attachments . iter ( ) )
7016
+ {
7017
+ assert_eq ! ( decoded. filename, original. filename) ;
7018
+ assert_eq ! ( decoded. content_digest, original. content_digest) ;
7019
+ assert_eq ! ( decoded. nonce, original. nonce) ;
7020
+ assert_eq ! ( decoded. scheme, original. scheme) ;
7021
+ assert_eq ! ( decoded. url, original. url) ;
7022
+ }
7023
+ }
6860
7024
}
0 commit comments