From 16c65492c7b42098265e23478f0f240f55c6a93f Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Fri, 2 Feb 2024 16:12:24 -0300 Subject: [PATCH 1/7] feat: add shouldPush method to ContentCodec interfaces and each codec type --- src/lib/ContentCodec.ts | 2 ++ src/lib/NativeCodecs/ReactionCodec.ts | 11 +++++++++++ src/lib/NativeCodecs/ReadReceiptCodec.ts | 4 ++++ src/lib/NativeCodecs/RemoteAttachmentCodec.ts | 4 ++++ src/lib/NativeCodecs/ReplyCodec.ts | 4 ++++ src/lib/NativeCodecs/StaticAttachmentCodec.ts | 4 ++++ src/lib/NativeCodecs/TextCodec.ts | 4 ++++ 7 files changed, 33 insertions(+) diff --git a/src/lib/ContentCodec.ts b/src/lib/ContentCodec.ts index b690dd7d8..15e83bb0f 100644 --- a/src/lib/ContentCodec.ts +++ b/src/lib/ContentCodec.ts @@ -101,6 +101,7 @@ export interface JSContentCodec { encode(content: T): EncodedContent decode(encodedContent: EncodedContent): T fallback(content: T): string | undefined + shouldPush(content: T): boolean } export interface NativeContentCodec { @@ -109,6 +110,7 @@ export interface NativeContentCodec { encode(content: T): NativeMessageContent decode(nativeContent: NativeMessageContent): T fallback(content: T): string | undefined + shouldPush(content: T): boolean } export type ContentCodec = JSContentCodec | NativeContentCodec diff --git a/src/lib/NativeCodecs/ReactionCodec.ts b/src/lib/NativeCodecs/ReactionCodec.ts index 9eabf8e6c..80b5fc6bd 100644 --- a/src/lib/NativeCodecs/ReactionCodec.ts +++ b/src/lib/NativeCodecs/ReactionCodec.ts @@ -35,4 +35,15 @@ export class ReactionCodec implements NativeContentCodec { return undefined } } + + shouldPush(content: ReactionContent): boolean { + switch (content.action) { + case 'added': + return true + case 'removed': + return false + default: + return false + } + } } diff --git a/src/lib/NativeCodecs/ReadReceiptCodec.ts b/src/lib/NativeCodecs/ReadReceiptCodec.ts index e99979e3c..cfcb8ad23 100644 --- a/src/lib/NativeCodecs/ReadReceiptCodec.ts +++ b/src/lib/NativeCodecs/ReadReceiptCodec.ts @@ -30,4 +30,8 @@ export class ReadReceiptCodec fallback(content: object): string | undefined { return undefined } + + shouldPush(content: object): boolean { + return false + } } diff --git a/src/lib/NativeCodecs/RemoteAttachmentCodec.ts b/src/lib/NativeCodecs/RemoteAttachmentCodec.ts index 026a2767c..354a52584 100644 --- a/src/lib/NativeCodecs/RemoteAttachmentCodec.ts +++ b/src/lib/NativeCodecs/RemoteAttachmentCodec.ts @@ -30,4 +30,8 @@ export class RemoteAttachmentCodec fallback(content: RemoteAttachmentContent): string | undefined { return `Can’t display "${content.filename}". This app doesn’t support attachments.` } + + shouldPush(content: RemoteAttachmentContent): boolean { + return true + } } diff --git a/src/lib/NativeCodecs/ReplyCodec.ts b/src/lib/NativeCodecs/ReplyCodec.ts index 10cecb4ce..c58bd016c 100644 --- a/src/lib/NativeCodecs/ReplyCodec.ts +++ b/src/lib/NativeCodecs/ReplyCodec.ts @@ -36,4 +36,8 @@ export class ReplyCodec implements NativeContentCodec { } return 'Replied to an earlier message' } + + shouldPush(content: ReplyContent): boolean { + return true + } } diff --git a/src/lib/NativeCodecs/StaticAttachmentCodec.ts b/src/lib/NativeCodecs/StaticAttachmentCodec.ts index c0c0acd3b..722d317d0 100644 --- a/src/lib/NativeCodecs/StaticAttachmentCodec.ts +++ b/src/lib/NativeCodecs/StaticAttachmentCodec.ts @@ -30,4 +30,8 @@ export class StaticAttachmentCodec fallback(content: StaticAttachmentContent): string | undefined { return `Can’t display "${content.filename}". This app doesn’t support attachments.` } + + shouldPush(content: StaticAttachmentContent): boolean { + return true + } } diff --git a/src/lib/NativeCodecs/TextCodec.ts b/src/lib/NativeCodecs/TextCodec.ts index f61101460..b85ca540b 100644 --- a/src/lib/NativeCodecs/TextCodec.ts +++ b/src/lib/NativeCodecs/TextCodec.ts @@ -27,4 +27,8 @@ export class TextCodec implements NativeContentCodec { fallback(content: string): string | undefined { return content } + + shouldPush(content: string): boolean { + return true + } } From 36c872d1343fb46e645a8b44f597830b50cf76d0 Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Fri, 2 Feb 2024 16:12:40 -0300 Subject: [PATCH 2/7] feat: add shouldPush property to DecodedMessage class --- src/lib/DecodedMessage.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lib/DecodedMessage.ts b/src/lib/DecodedMessage.ts index 103e3116c..07ed9043e 100644 --- a/src/lib/DecodedMessage.ts +++ b/src/lib/DecodedMessage.ts @@ -18,6 +18,7 @@ export class DecodedMessage { sent: number // timestamp in milliseconds nativeContent: NativeMessageContent fallback: string | undefined + shouldPush: boolean static from( json: string, @@ -32,7 +33,8 @@ export class DecodedMessage { decoded.senderAddress, decoded.sent, decoded.content, - decoded.fallback + decoded.fallback, + decoded.shouldPush ) } @@ -45,6 +47,7 @@ export class DecodedMessage { sent: number // timestamp in milliseconds content: any fallback: string | undefined + shouldPush: boolean }, client: Client ): DecodedMessage { @@ -56,7 +59,8 @@ export class DecodedMessage { object.senderAddress, object.sent, object.content, - object.fallback + object.fallback, + object.shouldPush ) } @@ -68,7 +72,8 @@ export class DecodedMessage { senderAddress: string, sent: number, content: any, - fallback: string | undefined + fallback: string | undefined, + shouldPush: boolean ) { this.client = client this.id = id @@ -78,6 +83,7 @@ export class DecodedMessage { this.sent = sent this.nativeContent = content this.fallback = fallback + this.shouldPush = shouldPush } content(): ContentTypes { From 2410b10508d67a9892c3d355e1b9430d1b340c5a Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Fri, 2 Feb 2024 16:13:14 -0300 Subject: [PATCH 3/7] feat: add shouldPush parameter to sendWithContentType and prepareMessageWithContentType functions --- src/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index b2039c9ef..9246e20e0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -235,12 +235,14 @@ export async function sendWithContentType( } else { const encodedContent = codec.encode(content) encodedContent.fallback = codec.fallback(content) + const shouldPush = codec.shouldPush(content) const encodedContentData = EncodedContent.encode(encodedContent).finish() return await XMTPModule.sendEncodedContent( clientAddress, conversationTopic, - Array.from(encodedContentData) + Array.from(encodedContentData), + shouldPush ) } } @@ -287,11 +289,13 @@ export async function prepareMessageWithContentType( } const encodedContent = codec.encode(content) encodedContent.fallback = codec.fallback(content) + const shouldPush = codec.shouldPush(content) const encodedContentData = EncodedContent.encode(encodedContent).finish() const preparedJson = await XMTPModule.prepareEncodedMessage( clientAddress, conversationTopic, - Array.from(encodedContentData) + Array.from(encodedContentData), + shouldPush ) return JSON.parse(preparedJson) } From f774147883da12912b3ce6df6ceb34eebeedc1f0 Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Fri, 2 Feb 2024 16:13:36 -0300 Subject: [PATCH 4/7] feat: add shouldPush test for content types --- example/src/tests.ts | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/example/src/tests.ts b/example/src/tests.ts index 814a091b3..c3ac51161 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -58,6 +58,10 @@ class NumberCodec implements JSContentCodec { fallback(content: NumberRef): string | undefined { return 'a billion' } + + shouldPush(content: NumberRef): boolean { + return false + } } export type Test = { @@ -808,6 +812,46 @@ test('register and use custom content types when preparing message', async () => return true }) +test('shouldPush for content types', async () => { + const bob = await Client.createRandom({ + env: 'local', + codecs: [new NumberCodec()], + }) + const alice = await Client.createRandom({ + env: 'local', + codecs: [new NumberCodec()], + }) + + bob.register(new NumberCodec()) + alice.register(new NumberCodec()) + + const bobConvo = await bob.conversations.newConversation(alice.address) + const aliceConvo = await alice.conversations.newConversation(bob.address) + + await bobConvo.send('hi') + + const messages = await aliceConvo.messages() + + const message = messages[0] + assert(message.shouldPush === true, 'shouldPush should be true') + + const prepped = await bobConvo.prepareMessage( + { topNumber: { bottomNumber: 12 } }, + { + contentType: ContentTypeNumber, + } + ) + + await bobConvo.sendPreparedMessage(prepped) + + const messages2 = await aliceConvo.messages() + const message2 = messages2[0] + + assert(message2.shouldPush === false, 'shouldPush should be false') + + return true +}) + test('calls preCreateIdentityCallback when supplied', async () => { let isCallbackCalled = false const preCreateIdentityCallback = () => { From 7450a4cadfaf11322fc6f55bbf592078d757da15 Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Fri, 2 Feb 2024 16:13:50 -0300 Subject: [PATCH 5/7] feat: add shouldPush parameter to sendEncodedContent and prepareEncodedMessage functions --- ios/Wrappers/DecodedMessageWrapper.swift | 1 + ios/XMTPModule.swift | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ios/Wrappers/DecodedMessageWrapper.swift b/ios/Wrappers/DecodedMessageWrapper.swift index 72d6c2368..5820d5334 100644 --- a/ios/Wrappers/DecodedMessageWrapper.swift +++ b/ios/Wrappers/DecodedMessageWrapper.swift @@ -13,6 +13,7 @@ struct DecodedMessageWrapper { "senderAddress": model.senderAddress, "sent": UInt64(model.sentAt.timeIntervalSince1970 * 1000), "fallback": model.encodedContent.fallback, + "shouldPush": model.shouldPush ] } diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 5ab661e2d..22aae0f65 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -226,14 +226,16 @@ public class XMTPModule: Module { ).toJson() } - AsyncFunction("sendEncodedContent") { (clientAddress: String, topic: String, encodedContentData: [UInt8]) -> String in + AsyncFunction("sendEncodedContent") { (clientAddress: String, topic: String, encodedContentData: [UInt8], shouldPush: Bool) -> String in guard let conversation = try await findConversation(clientAddress: clientAddress, topic: topic) else { throw Error.conversationNotFound("no conversation found for \(topic)") } let encodedContent = try EncodedContent(serializedData: Data(encodedContentData)) + + let options = SendOptions(contentType: encodedContent.type, shouldPush: shouldPush) - return try await conversation.send(encodedContent: encodedContent) + return try await conversation.send(encodedContent: encodedContent, options: options) } AsyncFunction("listConversations") { (clientAddress: String) -> [String] in @@ -390,15 +392,19 @@ public class XMTPModule: Module { AsyncFunction("prepareEncodedMessage") { ( clientAddress: String, conversationTopic: String, - encodedContentData: [UInt8] + encodedContentData: [UInt8], + shouldPush: Bool ) -> String in guard let conversation = try await findConversation(clientAddress: clientAddress, topic: conversationTopic) else { throw Error.conversationNotFound("no conversation found for \(conversationTopic)") } let encodedContent = try EncodedContent(serializedData: Data(encodedContentData)) + + let contentType = encodedContent.type let prepared = try await conversation.prepareMessage( - encodedContent: encodedContent + encodedContent: encodedContent, + options: SendOptions(contentType: contentType, shouldPush: shouldPush) ) let preparedAtMillis = prepared.envelopes[0].timestampNs / 1_000_000 let preparedData = try prepared.serializedData() From ccceabe988f0114cd3914de428b0cc459ad83d90 Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Mon, 19 Feb 2024 13:59:00 -0300 Subject: [PATCH 6/7] chore: update shouldPush parameter --- ios/Wrappers/DecodedMessageWrapper.swift | 2 +- ios/XMTPModule.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/Wrappers/DecodedMessageWrapper.swift b/ios/Wrappers/DecodedMessageWrapper.swift index 5820d5334..40514b1a2 100644 --- a/ios/Wrappers/DecodedMessageWrapper.swift +++ b/ios/Wrappers/DecodedMessageWrapper.swift @@ -13,7 +13,7 @@ struct DecodedMessageWrapper { "senderAddress": model.senderAddress, "sent": UInt64(model.sentAt.timeIntervalSince1970 * 1000), "fallback": model.encodedContent.fallback, - "shouldPush": model.shouldPush + "shouldPush": model.shouldPush as Any ] } diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 22aae0f65..28f0c69fa 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -233,7 +233,7 @@ public class XMTPModule: Module { let encodedContent = try EncodedContent(serializedData: Data(encodedContentData)) - let options = SendOptions(contentType: encodedContent.type, shouldPush: shouldPush) + let options = SendOptions(contentType: encodedContent.type, __shouldPush: shouldPush) return try await conversation.send(encodedContent: encodedContent, options: options) } @@ -404,7 +404,7 @@ public class XMTPModule: Module { let prepared = try await conversation.prepareMessage( encodedContent: encodedContent, - options: SendOptions(contentType: contentType, shouldPush: shouldPush) + options: SendOptions(contentType: contentType, __shouldPush: shouldPush) ) let preparedAtMillis = prepared.envelopes[0].timestampNs / 1_000_000 let preparedData = try prepared.serializedData() From bbe2696b8e16420f1168160ed074ef3d57366f7b Mon Sep 17 00:00:00 2001 From: kele-leanes Date: Tue, 20 Feb 2024 17:20:37 -0300 Subject: [PATCH 7/7] feat: add shouldPush parameter to sendEncodedContent and prepareEncodedMessage --- .../java/expo/modules/xmtpreactnativesdk/XMTPModule.kt | 8 +++++--- .../xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 4e79d8979..35489ec2f 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -321,7 +321,7 @@ class XMTPModule : Module() { ).toJson() } - AsyncFunction("sendEncodedContent") { clientAddress: String, topic: String, encodedContentData: List -> + AsyncFunction("sendEncodedContent") { clientAddress: String, topic: String, encodedContentData: List, shouldPush: Boolean -> val conversation = findConversation( clientAddress = clientAddress, @@ -338,8 +338,9 @@ class XMTPModule : Module() { } } val encodedContent = EncodedContent.parseFrom(encodedContentDataBytes) + val options = SendOptions(contentType = encodedContent.type, __shouldPush = shouldPush) - conversation.send(encodedContent = encodedContent) + conversation.send(encodedContent = encodedContent, options = options) } AsyncFunction("listConversations") { clientAddress: String -> @@ -456,7 +457,7 @@ class XMTPModule : Module() { ).toJson() } - AsyncFunction("prepareEncodedMessage") { clientAddress: String, conversationTopic: String, encodedContentData: List -> + AsyncFunction("prepareEncodedMessage") { clientAddress: String, conversationTopic: String, encodedContentData: List, shouldPush: Boolean -> logV("prepareEncodedMessage") val conversation = findConversation( @@ -478,6 +479,7 @@ class XMTPModule : Module() { val prepared = conversation.prepareMessage( encodedContent = encodedContent, + options = SendOptions(contentType = encodedContent.type, __shouldPush = shouldPush) ) val preparedAtMillis = prepared.envelopes[0].timestampNs / 1_000_000 val preparedFile = File.createTempFile(prepared.messageId, null) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt index 775ef66a5..4835dd1bd 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt @@ -20,7 +20,8 @@ class DecodedMessageWrapper { "content" to ContentJson(model.encodedContent).toJsonMap(), "senderAddress" to model.senderAddress, "sent" to model.sentAt.time, - "fallback" to model.encodedContent.fallback + "fallback" to model.encodedContent.fallback, + "shouldPush" to model.shouldPush as Any ) } }