From ed58e514d0b99de0dcf569788f054461cc484eac Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 10 Jan 2024 19:36:47 -0800 Subject: [PATCH] fix: return the entire json from custom content type and convert the base64 string back to bytes --- .../wrappers/ContentJson.kt | 8 ++-- example/package.json | 3 +- example/src/tests.ts | 40 +++++++++++++------ example/yarn.lock | 5 +++ package.json | 1 + src/lib/DecodedMessage.ts | 4 ++ 6 files changed, 44 insertions(+), 17 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ContentJson.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ContentJson.kt index 0521e2e8b..b46015697 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ContentJson.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ContentJson.kt @@ -51,8 +51,6 @@ class ContentJson( Client.register(RemoteAttachmentCodec()) Client.register(ReplyCodec()) Client.register(ReadReceiptCodec()) - // TODO: - //Client.register(CompositeCodec()) } fun fromJsonObject(obj: JsonObject): ContentJson { @@ -121,8 +119,8 @@ class ContentJson( return fromJsonObject(obj); } - fun bytesFrom64(bytes64: String): ByteArray = Base64.decode(bytes64, Base64.DEFAULT) - fun bytesTo64(bytes: ByteArray): String = Base64.encodeToString(bytes, Base64.DEFAULT) + fun bytesFrom64(bytes64: String): ByteArray = Base64.decode(bytes64, Base64.NO_WRAP) + fun bytesTo64(bytes: ByteArray): String = Base64.encodeToString(bytes, Base64.NO_WRAP) } fun toJsonMap(): Map { @@ -186,6 +184,8 @@ class ContentJson( json.addProperty("fallback", encodedContent.fallback) json.add("parameters", JsonParser.parseString(parameters)) json.add("type", typeJson) + json.addProperty("content", bytesTo64(encodedContent.content.toByteArray())) + } val encodedContentJSON = json.toString() if (encodedContentJSON.isNotBlank()) { diff --git a/example/package.json b/example/package.json index 6a99a5200..2024f4a39 100644 --- a/example/package.json +++ b/example/package.json @@ -28,7 +28,8 @@ "react-native-screens": "~3.20.0", "react-native-svg": "^13.9.0", "react-native-url-polyfill": "^2.0.0", - "react-query": "^3.39.3" + "react-query": "^3.39.3", + "text-encoding": "^0.7.0" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/example/src/tests.ts b/example/src/tests.ts index 101fc38af..94bd74803 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -1,5 +1,6 @@ import { content } from '@xmtp/proto' import ReactNativeBlobUtil from 'react-native-blob-util' +import { TextEncoder, TextDecoder } from 'text-encoding' import { DecodedMessage } from 'xmtp-react-native-sdk/lib/DecodedMessage' import { @@ -24,25 +25,37 @@ const ContentTypeNumber: ContentTypeId = { versionMinor: 0, } -class NumberCodec implements JSContentCodec { +export type NumberRef = { + topNumber: { + bottomNumber: number + } +} + +class NumberCodec implements JSContentCodec { contentType = ContentTypeNumber // a completely absurd way of encoding number values - encode(content: number): EncodedContent { + encode(content: NumberRef): EncodedContent { return { type: ContentTypeNumber, parameters: { - number: JSON.stringify(content), + test: 'test', }, - content: new Uint8Array(), + content: new TextEncoder().encode(JSON.stringify(content)), } } - decode(encodedContent: EncodedContent): number { - return JSON.parse(encodedContent.parameters.number) as number + decode(encodedContent: EncodedContent): NumberRef { + if (encodedContent.parameters.test !== 'test') { + throw new Error(`parameters should parse ${encodedContent.parameters}`) + } + const contentReceived = JSON.parse( + new TextDecoder().decode(encodedContent.content) + ) as NumberRef + return contentReceived } - fallback(content: number): string | undefined { + fallback(content: NumberRef): string | undefined { return 'a billion' } } @@ -772,9 +785,12 @@ test('register and use custom content types when preparing message', async () => const bobConvo = await bob.conversations.newConversation(alice.address) const aliceConvo = await alice.conversations.newConversation(bob.address) - const prepped = await bobConvo.prepareMessage(12, { - contentType: ContentTypeNumber, - }) + const prepped = await bobConvo.prepareMessage( + { topNumber: { bottomNumber: 12 } }, + { + contentType: ContentTypeNumber, + } + ) await bobConvo.sendPreparedMessage(prepped) @@ -782,10 +798,10 @@ test('register and use custom content types when preparing message', async () => assert(messages.length === 1, 'did not get messages') const message = messages[0] - const messageContent = message.content() + const messageContent = message.content() as NumberRef assert( - messageContent === 12, + messageContent.topNumber.bottomNumber === 12, 'did not get content properly: ' + JSON.stringify(messageContent) ) diff --git a/example/yarn.lock b/example/yarn.lock index f58129694..8ba3f845b 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -8458,6 +8458,11 @@ terser@^5.15.0: commander "^2.20.0" source-map-support "~0.5.20" +text-encoding@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643" + integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" diff --git a/package.json b/package.json index 01b8d1459..92f0d70f1 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "dependencies": { "@msgpack/msgpack": "^3.0.0-beta2", "@xmtp/proto": "^3.25.0", + "buffer": "^6.0.3", "ethers": "^5.7.2" }, "devDependencies": { diff --git a/src/lib/DecodedMessage.ts b/src/lib/DecodedMessage.ts index c348cacc5..103e3116c 100644 --- a/src/lib/DecodedMessage.ts +++ b/src/lib/DecodedMessage.ts @@ -7,6 +7,7 @@ import { } from './ContentCodec' import { ReplyCodec } from './NativeCodecs/ReplyCodec' import { TextCodec } from './NativeCodecs/TextCodec' +import { Buffer } from 'buffer' export class DecodedMessage { client: Client @@ -91,6 +92,9 @@ export class DecodedMessage { `no content type found ${JSON.stringify(this.contentTypeId)}` ) } + if (encoded.content) { + encoded.content = new Uint8Array(Buffer.from(encoded.content, 'base64')) + } return codec.decode(encoded) } else { for (const codec of Object.values(this.client.codecRegistry)) {