Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add shouldPush to contentTypes messages #235

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ class XMTPModule : Module() {
).toJson()
}

AsyncFunction("sendEncodedContent") { clientAddress: String, topic: String, encodedContentData: List<Int> ->
AsyncFunction("sendEncodedContent") { clientAddress: String, topic: String, encodedContentData: List<Int>, shouldPush: Boolean ->
val conversation =
findConversation(
clientAddress = clientAddress,
Expand All @@ -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 ->
Expand Down Expand Up @@ -456,7 +457,7 @@ class XMTPModule : Module() {
).toJson()
}

AsyncFunction("prepareEncodedMessage") { clientAddress: String, conversationTopic: String, encodedContentData: List<Int> ->
AsyncFunction("prepareEncodedMessage") { clientAddress: String, conversationTopic: String, encodedContentData: List<Int>, shouldPush: Boolean ->
logV("prepareEncodedMessage")
val conversation =
findConversation(
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
}
}
44 changes: 44 additions & 0 deletions example/src/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ class NumberCodec implements JSContentCodec<NumberRef> {
fallback(content: NumberRef): string | undefined {
return 'a billion'
}

shouldPush(content: NumberRef): boolean {
return false
}
}

export type Test = {
Expand Down Expand Up @@ -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 = () => {
Expand Down
1 change: 1 addition & 0 deletions ios/Wrappers/DecodedMessageWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct DecodedMessageWrapper {
"senderAddress": model.senderAddress,
"sent": UInt64(model.sentAt.timeIntervalSince1970 * 1000),
"fallback": model.encodedContent.fallback,
"shouldPush": model.shouldPush as Any
]
}

Expand Down
14 changes: 10 additions & 4 deletions ios/XMTPModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
8 changes: 6 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,14 @@ export async function sendWithContentType<T>(
} 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
)
}
}
Expand Down Expand Up @@ -287,11 +289,13 @@ export async function prepareMessageWithContentType<T>(
}
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)
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/ContentCodec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { content } from '@xmtp/proto'

Check warning on line 1 in src/lib/ContentCodec.ts

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups
import { ReadReceiptCodec } from './NativeCodecs/ReadReceiptCodec'

Check warning on line 2 in src/lib/ContentCodec.ts

View workflow job for this annotation

GitHub Actions / lint

'ReadReceiptCodec' is defined but never used
import { TextCodec } from './NativeCodecs/TextCodec'

Check warning on line 3 in src/lib/ContentCodec.ts

View workflow job for this annotation

GitHub Actions / lint

'TextCodec' is defined but never used
import { ReplyCodec } from './NativeCodecs/ReplyCodec'

Check warning on line 4 in src/lib/ContentCodec.ts

View workflow job for this annotation

GitHub Actions / lint

`./NativeCodecs/ReplyCodec` import should occur before import of `./NativeCodecs/TextCodec`

Check warning on line 4 in src/lib/ContentCodec.ts

View workflow job for this annotation

GitHub Actions / lint

'ReplyCodec' is defined but never used

export type EncodedContent = content.EncodedContent
export type ContentTypeId = content.ContentTypeId
Expand Down Expand Up @@ -101,6 +101,7 @@
encode(content: T): EncodedContent
decode(encodedContent: EncodedContent): T
fallback(content: T): string | undefined
shouldPush(content: T): boolean
}

export interface NativeContentCodec<T> {
Expand All @@ -109,6 +110,7 @@
encode(content: T): NativeMessageContent
decode(nativeContent: NativeMessageContent): T
fallback(content: T): string | undefined
shouldPush(content: T): boolean
}

export type ContentCodec<T> = JSContentCodec<T> | NativeContentCodec<T>
12 changes: 9 additions & 3 deletions src/lib/DecodedMessage.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Client } from './Client'
import {
ContentCodec,

Check warning on line 3 in src/lib/DecodedMessage.ts

View workflow job for this annotation

GitHub Actions / lint

'ContentCodec' is defined but never used
JSContentCodec,
NativeContentCodec,
NativeMessageContent,
} from './ContentCodec'
import { ReplyCodec } from './NativeCodecs/ReplyCodec'

Check warning on line 8 in src/lib/DecodedMessage.ts

View workflow job for this annotation

GitHub Actions / lint

'ReplyCodec' is defined but never used
import { TextCodec } from './NativeCodecs/TextCodec'

Check warning on line 9 in src/lib/DecodedMessage.ts

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups

Check warning on line 9 in src/lib/DecodedMessage.ts

View workflow job for this annotation

GitHub Actions / lint

'TextCodec' is defined but never used
import { Buffer } from 'buffer'

export class DecodedMessage<ContentTypes = any> {
Expand All @@ -18,6 +18,7 @@
sent: number // timestamp in milliseconds
nativeContent: NativeMessageContent
fallback: string | undefined
shouldPush: boolean

static from<ContentTypes>(
json: string,
Expand All @@ -32,7 +33,8 @@
decoded.senderAddress,
decoded.sent,
decoded.content,
decoded.fallback
decoded.fallback,
decoded.shouldPush
)
}

Expand All @@ -45,6 +47,7 @@
sent: number // timestamp in milliseconds
content: any
fallback: string | undefined
shouldPush: boolean
},
client: Client<ContentTypes>
): DecodedMessage<ContentTypes> {
Expand All @@ -56,7 +59,8 @@
object.senderAddress,
object.sent,
object.content,
object.fallback
object.fallback,
object.shouldPush
)
}

Expand All @@ -68,7 +72,8 @@
senderAddress: string,
sent: number,
content: any,
fallback: string | undefined
fallback: string | undefined,
shouldPush: boolean
) {
this.client = client
this.id = id
Expand All @@ -78,6 +83,7 @@
this.sent = sent
this.nativeContent = content
this.fallback = fallback
this.shouldPush = shouldPush
}

content(): ContentTypes {
Expand Down
11 changes: 11 additions & 0 deletions src/lib/NativeCodecs/ReactionCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,15 @@ export class ReactionCodec implements NativeContentCodec<ReactionContent> {
return undefined
}
}

shouldPush(content: ReactionContent): boolean {
switch (content.action) {
case 'added':
return true
case 'removed':
return false
default:
return false
}
}
}
4 changes: 4 additions & 0 deletions src/lib/NativeCodecs/ReadReceiptCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ export class ReadReceiptCodec
fallback(content: object): string | undefined {
return undefined
}

shouldPush(content: object): boolean {
return false
}
}
4 changes: 4 additions & 0 deletions src/lib/NativeCodecs/RemoteAttachmentCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
4 changes: 4 additions & 0 deletions src/lib/NativeCodecs/ReplyCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ export class ReplyCodec implements NativeContentCodec<ReplyContent> {
}
return 'Replied to an earlier message'
}

shouldPush(content: ReplyContent): boolean {
return true
}
}
4 changes: 4 additions & 0 deletions src/lib/NativeCodecs/StaticAttachmentCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
4 changes: 4 additions & 0 deletions src/lib/NativeCodecs/TextCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ export class TextCodec implements NativeContentCodec<string> {
fallback(content: string): string | undefined {
return content
}

shouldPush(content: string): boolean {
return true
}
}
Loading