diff --git a/src/pages/docs/chat/rooms/messages.mdx b/src/pages/docs/chat/rooms/messages.mdx
index 409430dfef..b210d28d0c 100644
--- a/src/pages/docs/chat/rooms/messages.mdx
+++ b/src/pages/docs/chat/rooms/messages.mdx
@@ -228,6 +228,90 @@ fun MyComponent(room: Room) {
```
+### Handle self-published messages
+
+
+
+
+```javascript
+const {unsubscribe} = room.messages.subscribe((event) => {
+ // Early return if a message with the same serial and version.serial already exists
+ const existingMessage = myMessageList.find(msg => msg.serial === event.message.serial);
+ if (existingMessage && existingMessage.version.serial === event.message.version.serial) {
+ return;
+ }
+ // Process the message
+});
+```
+
+```react
+import { useMessages } from '@ably/chat/react';
+
+const MyComponent = () => {
+ useMessages({
+ listener: (event) => {
+ // Early return if a message with the same serial and version.serial already exists
+ const existingMessage = myMessageList.find(msg => msg.serial === event.message.serial);
+ if (existingMessage && existingMessage.version.serial === event.message.version.serial) {
+ return;
+ }
+ // Process the message
+ },
+ });
+
+ return ...
;
+};
+```
+
+```swift
+let messagesList: [Message]
+let messagesSubscription = try await room.messages.subscribe()
+for await message in messagesSubscription {
+ // Early return if a message with the same serial and version already exists
+ let existingMessage = messagesList.first(where: { $0.serial == message.serial })
+ if existingMessage != nil && existingMessage?.version.serial == message.version.serial {
+ continue
+ }
+ // Process the message
+}
+```
+
+```kotlin
+val myMessageList: List
+val subscription = room.messages.subscribe { event: ChatMessageEvent ->
+ // Early return if a message with the same serial and version.serial already exists
+ val existingMessage = myMessageList.find { it.serial == event.message.serial }
+ if (existingMessage != null && existingMessage.version.serial == event.message.version.serial) return@subscribe
+ // Process the message
+}
+```
+
+```android
+import androidx.compose.runtime.*
+import com.ably.chat.Message
+import com.ably.chat.Room
+import com.ably.chat.asFlow
+
+@Composable
+fun MyComponent(room: Room) {
+ var myMessageList by remember { mutableStateOf>(emptyList()) }
+
+ LaunchedEffect(room) {
+ room.messages.asFlow().collect { event ->
+ // Early return if a message with the same serial and version.serial already exists
+ val existingMessage = myMessageList.find { it.serial == event.message.serial }
+ if (existingMessage != null && existingMessage.version.serial == event.message.version.serial) return@collect
+ // Process the message
+ }
+ }
+}
+```
+
+
## Get a single message
@@ -378,13 +462,18 @@ Use the [`useMessages`](https://sdk.ably.com/builds/ably/ably-chat-js/main/typed
```javascript
import { ChatMessageEventType } from '@ably/chat';
const {unsubscribe} = room.messages.subscribe((event) => {
+ // Early return if a message with the same serial and version.serial already exists
+ const existingMessage = myMessageList.find(msg => msg.serial === event.message.serial);
+ if (existingMessage && existingMessage.version.serial === event.message.version.serial) {
+ return;
+ }
+
switch (event.type) {
case ChatMessageEventType.Created:
console.log('Received message: ', event.message);
break;
case ChatMessageEventType.Updated:
- const existing = myMessageList.find(msg => msg.serial === event.message.serial);
- if (existing && event.message.version.serial <= existing.version.serial) {
+ if (existingMessage && event.message.version.serial <= existingMessage.version.serial) {
// We've already received a more recent update, so this one can be discarded.
return;
}
@@ -404,13 +493,18 @@ import { useMessages } from '@ably/chat/react';
const MyComponent = () => {
useMessages({
listener: (event) => {
+ // Early return if a message with the same serial and version.serial already exists
+ const existingMessage = myMessageList.find(msg => msg.serial === event.message.serial);
+ if (existingMessage && existingMessage.version.serial === event.message.version.serial) {
+ return;
+ }
+
switch (event.type) {
case ChatMessageEventType.Created:
console.log('Received message: ', event.message);
break;
case ChatMessageEventType.Updated:
- const existing = myMessageList.find(msg => msg.serial === event.message.serial);
- if (existing && event.message.version.serial <= existing.version.serial) {
+ if (existingMessage && event.message.version.serial <= existingMessage.version.serial) {
// We've already received a more recent update, so this one can be discarded.
return;
}
@@ -431,12 +525,19 @@ const MyComponent = () => {
let messagesList: [Message]
let messagesSubscription = try await room.messages.subscribe()
for await message in messagesSubscription {
+ // Early return if a message with the same serial and version already exists
+ let existingMessage = messagesList.first(where: { $0.serial == message.serial })
+ if existingMessage != nil && existingMessage?.version.serial == message.version.serial {
+ continue
+ }
+
switch message.action {
case .messageCreate:
messagesList.append(message)
case .messageUpdate:
// compare versions to ensure you are only updating with a newer message
- if let index = messagesList.firstIndex(where: { $0.serial == message.serial && message.version > $0.version }) {
+ if let existingMessage = existingMessage, message.version > existingMessage.version,
+ let index = messagesList.firstIndex(of: existingMessage) {
messagesList[index] = message
}
default:
@@ -448,11 +549,17 @@ for await message in messagesSubscription {
```kotlin
val myMessageList: List
val messagesSubscription = room.messages.subscribe { event ->
+ // Early return if a message with the same serial and version.serial already exists
+ val existingMessage = myMessageList.find { it.serial == event.message.serial }
+ if (existingMessage != null && existingMessage.version.serial == event.message.version.serial) return@subscribe
+
when (event.type) {
ChatMessageEventType.Created -> println("Received message: ${event.message}")
- ChatMessageEventType.Updated -> myMessageList.find {
- event.message.serial == it.serial && event.message.version.serial > it.version.serial
- }?.let { println("Message updated: ${event.message}") }
+ ChatMessageEventType.Updated -> {
+ if (existingMessage != null && event.message.version.serial > existingMessage.version.serial) {
+ println("Message updated: ${event.message}")
+ }
+ }
else -> {}
}
}
@@ -471,18 +578,17 @@ fun MyComponent(room: Room) {
LaunchedEffect(room) {
room.messages.asFlow().collect { event ->
+ // Early return if a message with the same serial and version.serial already exists
+ val existingMessage = myMessageList.find { it.serial == event.message.serial }
+ if (existingMessage != null && existingMessage.version.serial == event.message.version.serial) return@collect
+
when (event.type) {
ChatMessageEventType.Created -> {
myMessageList = myMessageList + event.message
}
ChatMessageEventType.Updated -> {
- myMessageList = myMessageList.map { message ->
- if (message.serial == event.message.serial &&
- event.message.version.serial > message.version.serial) {
- event.message
- } else {
- message
- }
+ if (existingMessage != null && event.message.version.serial > existingMessage.version.serial) {
+ myMessageList = myMessageList.map { if (it.serial == existingMessage.serial) event.message else it }
}
}
else -> {}
@@ -632,13 +738,18 @@ Use the [`useMessages`](https://sdk.ably.com/builds/ably/ably-chat-js/main/typed
```javascript
import { ChatMessageEventType } from '@ably/chat';
const {unsubscribe} = room.messages.subscribe((event) => {
+ // Early return if a message with the same serial and version.serial already exists
+ const existingMessage = myMessageList.find(msg => msg.serial === event.message.serial);
+ if (existingMessage && existingMessage.version.serial === event.message.version.serial) {
+ return;
+ }
+
switch (event.type) {
case ChatMessageEventType.Created:
console.log('Received message: ', event.message);
break;
case ChatMessageEventType.Deleted:
- const existing = myMessageList.find(msg => msg.serial === event.message.serial);
- if (existing && event.message.version.serial <= existing.version.serial) {
+ if (existingMessage && event.message.version.serial <= existingMessage.version.serial) {
// We've already received a more recent update, so this one can be discarded.
return;
}
@@ -658,13 +769,18 @@ import { useMessages } from '@ably/chat/react';
const MyComponent = () => {
useMessages({
listener: (event) => {
+ // Early return if a message with the same serial and version.serial already exists
+ const existingMessage = myMessageList.find(msg => msg.serial === event.message.serial);
+ if (existingMessage && existingMessage.version.serial === event.message.version.serial) {
+ return;
+ }
+
switch (event.type) {
case ChatMessageEventType.Created:
console.log('Received message: ', event.message);
break;
case ChatMessageEventType.Deleted:
- const existing = myMessageList.find(msg => msg.serial === event.message.serial);
- if (existing && event.message.version.serial <= existing.version.serial) {
+ if (existingMessage && event.message.version.serial <= existingMessage.version.serial) {
// We've already received a more recent update, so this one can be discarded.
return;
}
@@ -685,12 +801,19 @@ const MyComponent = () => {
let messagesList: [Message]
let messagesSubscription = try await room.messages.subscribe()
for await message in messagesSubscription {
+ // Early return if a message with the same serial and version already exists
+ let existingMessage = messagesList.first(where: { $0.serial == message.serial })
+ if existingMessage != nil && existingMessage?.version.serial == message.version.serial {
+ continue
+ }
+
switch message.action {
case .messageCreate:
messagesList.append(message)
case .messageDelete:
// version check ensures the message you are deleting is older
- if let index = messagesList.firstIndex(where: { $0.serial == message.serial && message.version > $0.version }) {
+ if let existingMessage = existingMessage, message.version > existingMessage.version,
+ let index = messagesList.firstIndex(of: existingMessage) {
messagesList.remove(at: index)
}
default:
@@ -702,11 +825,17 @@ for await message in messagesSubscription {
```kotlin
val myMessageList: List
val messagesSubscription = room.messages.subscribe { event ->
+ // Early return if a message with the same serial and version.serial already exists
+ val existingMessage = myMessageList.find { it.serial == event.message.serial }
+ if (existingMessage != null && existingMessage.version.serial == event.message.version.serial) return@subscribe
+
when (event.type) {
ChatMessageEventType.Created -> println("Received message: ${event.message}")
- ChatMessageEventType.Deleted -> myMessageList.find {
- event.message.serial == it.serial && event.message.version.serial > it.version.serial
- }?.let { println("Message deleted: ${event.message}") }
+ ChatMessageEventType.Deleted -> {
+ if (existingMessage != null && event.message.version.serial > existingMessage.version.serial) {
+ println("Message deleted: ${event.message}")
+ }
+ }
else -> {}
}
}
@@ -725,14 +854,17 @@ fun MyComponent(room: Room) {
LaunchedEffect(room) {
room.messages.asFlow().collect { event ->
+ // Early return if a message with the same serial and version.serial already exists
+ val existingMessage = myMessageList.find { it.serial == event.message.serial }
+ if (existingMessage != null && existingMessage.version.serial == event.message.version.serial) return@collect
+
when (event.type) {
ChatMessageEventType.Created -> {
myMessageList = myMessageList + event.message
}
ChatMessageEventType.Deleted -> {
- myMessageList = myMessageList.filterNot { message ->
- message.serial == event.message.serial &&
- event.message.version.serial > message.version.serial
+ if (existingMessage != null && event.message.version.serial > existingMessage.version.serial) {
+ myMessageList = myMessageList.filterNot { it.serial == existingMessage.serial }
}
}
else -> {}
@@ -832,15 +964,22 @@ let myMessageList: Message[];
// For messages (create, update, delete)
room.messages.subscribe((event) => {
+ const existingMessage = myMessageList.find((msg) => msg.serial === event.message.serial);
+
+ // Early return if a message with the same serial and version.serial already exists
+ if (existingMessage && existingMessage.version.serial === event.message.version.serial) {
+ return;
+ }
+
switch (event.type) {
case ChatMessageEventType.Created:
myMessageList.push(event.message);
break;
case ChatMessageEventType.Updated:
case ChatMessageEventType.Deleted:
- const idx = myMessageList.findIndex((msg) => msg.serial === event.message.serial);
- if (idx !== -1) {
- myMessageList[idx] = myMessageList[idx].with(event);
+ if (existingMessage) {
+ const idx = myMessageList.indexOf(existingMessage);
+ myMessageList[idx] = existingMessage.with(event);
}
break;
default:
@@ -850,9 +989,10 @@ room.messages.subscribe((event) => {
// And for message reactions
room.messages.reactions.subscribe((event) => {
- const idx = myMessageList.findIndex((msg) => msg.serial === event.messageSerial);
- if (idx !== -1) {
- myMessageList[idx] = myMessageList[idx].with(event);
+ const existingMessage = myMessageList.find((msg) => msg.serial === event.messageSerial);
+ if (existingMessage) {
+ const idx = myMessageList.indexOf(existingMessage);
+ myMessageList[idx] = existingMessage.with(event);
}
});
```
@@ -867,35 +1007,39 @@ const MyComponent = () => {
const [ messages, setMessages ] = useState<{list: Message[]}>({list: []});
useMessages({
listener: (event) => {
- switch (event.type) {
- case ChatMessageEventType.Created:
- setMessages((prev) => {
+ setMessages((prev) => {
+ const existingMessage = prev.list.find((msg) => msg.serial === event.message.serial);
+
+ // Early return if a message with the same serial and version.serial already exists
+ if (existingMessage && existingMessage.version.serial === event.message.version.serial) {
+ return prev;
+ }
+
+ switch (event.type) {
+ case ChatMessageEventType.Created:
// append new message
prev.list.push(event.message);
// update reference without copying whole array
return { list: prev.list };
- });
- break;
- case ChatMessageEventType.Updated:
- case ChatMessageEventType.Deleted:
- setMyMessageList((prev) => {
- // find existing message to apply update or delete to
- const existing = prev.list.findIndex((msg) => msg.serial === event.message.serial);
- if (existing === -1) {
+ case ChatMessageEventType.Updated:
+ case ChatMessageEventType.Deleted:
+ if (!existingMessage) {
return prev; // no change if not found
}
- const newMsg = existing.with(event);
- if (newMsg === existing) {
+ const newMsg = existingMessage.with(event);
+ if (newMsg === existingMessage) {
// with() returns the same object if the event is older,
// so in this case no change is needed
return prev;
}
// set new message and update reference without copying whole array
- prev.list[existing] = newMsg;
+ const idx = prev.list.indexOf(existingMessage);
+ prev.list[idx] = newMsg;
return { list: prev.list };
- });
- break;
- }
+ default:
+ return prev;
+ }
+ });
},
});