mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 13:49:53 +01:00
Merge branch '1779-headless-messages-sent-acked' into 'master'
Expose message delivery state changes to websockets API Closes #1779 See merge request briar/briar!1284
This commit is contained in:
@@ -410,3 +410,39 @@ When the last connection is lost (the contact goes offline), it sends a `Contact
|
|||||||
"type": "event"
|
"type": "event"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### A message was sent
|
||||||
|
|
||||||
|
When Briar sent a message to a contact, it sends a `MessagesSentEvent`. This is indicated in Briar
|
||||||
|
by showing one tick next to the message.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"contactId": 1,
|
||||||
|
"messageIds": [
|
||||||
|
"+AIMMgOCPFF8HDEhiEHYjbfKrg7v0G94inKxjvjYzA8="
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "MessagesSentEvent",
|
||||||
|
"type": "event"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### A message was acknowledged
|
||||||
|
|
||||||
|
When a contact acknowledges that they received a message, Briar sends a `MessagesAckedEvent`.
|
||||||
|
This is indicated in Briar by showing two ticks next to the message.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"contactId": 1,
|
||||||
|
"messageIds": [
|
||||||
|
"+AIMMgOCPFF8HDEhiEHYjbfKrg7v0G94inKxjvjYzA8="
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "MessagesAckedEvent",
|
||||||
|
"type": "event"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import org.briarproject.bramble.api.db.DatabaseExecutor
|
|||||||
import org.briarproject.bramble.api.db.NoSuchContactException
|
import org.briarproject.bramble.api.db.NoSuchContactException
|
||||||
import org.briarproject.bramble.api.event.Event
|
import org.briarproject.bramble.api.event.Event
|
||||||
import org.briarproject.bramble.api.event.EventListener
|
import org.briarproject.bramble.api.event.EventListener
|
||||||
|
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent
|
||||||
|
import org.briarproject.bramble.api.sync.event.MessagesSentEvent
|
||||||
import org.briarproject.bramble.api.system.Clock
|
import org.briarproject.bramble.api.system.Clock
|
||||||
import org.briarproject.bramble.util.StringUtils.utf8IsTooLong
|
import org.briarproject.bramble.util.StringUtils.utf8IsTooLong
|
||||||
import org.briarproject.briar.api.blog.BlogInvitationRequest
|
import org.briarproject.briar.api.blog.BlogInvitationRequest
|
||||||
@@ -39,6 +41,8 @@ import javax.inject.Inject
|
|||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
internal const val EVENT_CONVERSATION_MESSAGE = "ConversationMessageReceivedEvent"
|
internal const val EVENT_CONVERSATION_MESSAGE = "ConversationMessageReceivedEvent"
|
||||||
|
internal const val EVENT_MESSAGES_ACKED = "MessagesAckedEvent"
|
||||||
|
internal const val EVENT_MESSAGES_SENT = "MessagesSentEvent"
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -90,6 +94,12 @@ constructor(
|
|||||||
webSocketController.sendEvent(EVENT_CONVERSATION_MESSAGE, e.output())
|
webSocketController.sendEvent(EVENT_CONVERSATION_MESSAGE, e.output())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is MessagesSentEvent -> {
|
||||||
|
webSocketController.sendEvent(EVENT_MESSAGES_SENT, e.output())
|
||||||
|
}
|
||||||
|
is MessagesAckedEvent -> {
|
||||||
|
webSocketController.sendEvent(EVENT_MESSAGES_ACKED, e.output())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package org.briarproject.briar.headless.messaging
|
package org.briarproject.briar.headless.messaging
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId
|
import org.briarproject.bramble.api.contact.ContactId
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId
|
||||||
|
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent
|
||||||
|
import org.briarproject.bramble.api.sync.event.MessagesSentEvent
|
||||||
import org.briarproject.briar.api.conversation.ConversationMessageHeader
|
import org.briarproject.briar.api.conversation.ConversationMessageHeader
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessage
|
import org.briarproject.briar.api.messaging.PrivateMessage
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader
|
||||||
@@ -43,3 +46,15 @@ internal fun PrivateMessage.output(contactId: ContactId, text: String) = JsonDic
|
|||||||
"groupId" to message.groupId.bytes,
|
"groupId" to message.groupId.bytes,
|
||||||
"text" to text
|
"text" to text
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal fun MessagesAckedEvent.output() = JsonDict(
|
||||||
|
"contactId" to contactId.int,
|
||||||
|
"messageIds" to messageIds.toJson()
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun MessagesSentEvent.output() = JsonDict(
|
||||||
|
"contactId" to contactId.int,
|
||||||
|
"messageIds" to messageIds.toJson()
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun Collection<MessageId>.toJson() = map { it.bytes }
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ import org.briarproject.bramble.api.db.NoSuchContactException
|
|||||||
import org.briarproject.bramble.api.identity.AuthorInfo
|
import org.briarproject.bramble.api.identity.AuthorInfo
|
||||||
import org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED
|
import org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED
|
||||||
import org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED
|
import org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId
|
||||||
|
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent
|
||||||
|
import org.briarproject.bramble.api.sync.event.MessagesSentEvent
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor
|
import org.briarproject.bramble.test.ImmediateExecutor
|
||||||
import org.briarproject.bramble.test.TestUtils.getRandomId
|
import org.briarproject.bramble.test.TestUtils.getRandomId
|
||||||
import org.briarproject.bramble.util.StringUtils.getRandomString
|
import org.briarproject.bramble.util.StringUtils.getRandomString
|
||||||
import org.briarproject.briar.api.client.SessionId
|
import org.briarproject.briar.api.client.SessionId
|
||||||
import org.briarproject.briar.api.conversation.ConversationManager
|
|
||||||
import org.briarproject.briar.api.introduction.IntroductionRequest
|
import org.briarproject.briar.api.introduction.IntroductionRequest
|
||||||
import org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH
|
import org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH
|
||||||
import org.briarproject.briar.api.messaging.MessagingManager
|
import org.briarproject.briar.api.messaging.MessagingManager
|
||||||
@@ -100,6 +102,40 @@ internal class MessagingControllerImplTest : ControllerTest() {
|
|||||||
testInvalidContactId { controller.list(ctx) }
|
testInvalidContactId { controller.list(ctx) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMessagesAckedEvent() {
|
||||||
|
val messageId1 = MessageId(getRandomId())
|
||||||
|
val messageId2 = MessageId(getRandomId())
|
||||||
|
val messageIds = listOf(messageId1, messageId2)
|
||||||
|
val event = MessagesAckedEvent(contact.id, messageIds)
|
||||||
|
|
||||||
|
every {
|
||||||
|
webSocketController.sendEvent(
|
||||||
|
EVENT_MESSAGES_ACKED,
|
||||||
|
event.output()
|
||||||
|
)
|
||||||
|
} just runs
|
||||||
|
|
||||||
|
controller.eventOccurred(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMessagesSentEvent() {
|
||||||
|
val messageId1 = MessageId(getRandomId())
|
||||||
|
val messageId2 = MessageId(getRandomId())
|
||||||
|
val messageIds = listOf(messageId1, messageId2)
|
||||||
|
val event = MessagesSentEvent(contact.id, messageIds)
|
||||||
|
|
||||||
|
every {
|
||||||
|
webSocketController.sendEvent(
|
||||||
|
EVENT_MESSAGES_SENT,
|
||||||
|
event.output()
|
||||||
|
)
|
||||||
|
} just runs
|
||||||
|
|
||||||
|
controller.eventOccurred(event)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun listNonexistentContactId() {
|
fun listNonexistentContactId() {
|
||||||
testNonexistentContactId { controller.list(ctx) }
|
testNonexistentContactId { controller.list(ctx) }
|
||||||
@@ -177,6 +213,43 @@ internal class MessagingControllerImplTest : ControllerTest() {
|
|||||||
controller.eventOccurred(event)
|
controller.eventOccurred(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOutputMessagesAckedEvent() {
|
||||||
|
val messageId1 = MessageId(getRandomId())
|
||||||
|
val messageId2 = MessageId(getRandomId())
|
||||||
|
val messageIds = listOf(messageId1, messageId2)
|
||||||
|
val event = MessagesAckedEvent(contact.id, messageIds)
|
||||||
|
val json = """
|
||||||
|
{
|
||||||
|
"contactId": ${contact.id.int},
|
||||||
|
"messageIds": [
|
||||||
|
${toJson(messageId1.bytes)},
|
||||||
|
${toJson(messageId2.bytes)}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
assertJsonEquals(json, event.output())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOutputMessagesSentEvent() {
|
||||||
|
val messageId1 = MessageId(getRandomId())
|
||||||
|
val messageId2 = MessageId(getRandomId())
|
||||||
|
val messageIds = listOf(messageId1, messageId2)
|
||||||
|
val event = MessagesSentEvent(contact.id, messageIds)
|
||||||
|
|
||||||
|
val json = """
|
||||||
|
{
|
||||||
|
"contactId": ${contact.id.int},
|
||||||
|
"messageIds": [
|
||||||
|
${toJson(messageId1.bytes)},
|
||||||
|
${toJson(messageId2.bytes)}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
assertJsonEquals(json, event.output())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOutputPrivateMessageHeader() {
|
fun testOutputPrivateMessageHeader() {
|
||||||
val json = """
|
val json = """
|
||||||
|
|||||||
Reference in New Issue
Block a user