mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
[headless] make events related to adding contacts available via websocket
This commit is contained in:
@@ -274,8 +274,51 @@ it will send a JSON object to connected websocket clients:
|
||||
Note that the JSON object in `data` is exactly what the REST API returns
|
||||
when listing private messages.
|
||||
|
||||
# TODO
|
||||
### A new contact was added remotely
|
||||
|
||||
* PendingContactStateChangedEvent
|
||||
* PendingContactRemovedEvent
|
||||
* ContactAddedRemotelyEvent
|
||||
When the Briar peer adds a new contact remotely,
|
||||
it will send a JSON object representing the new contact to connected websocket clients:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"author": {
|
||||
"formatVersion": 1,
|
||||
"id": "y1wkIzAimAbYoCGgWxkWlr6vnq1F8t1QRA/UMPgI0E0=",
|
||||
"name": "Test",
|
||||
"publicKey": "BDu6h1S02bF4W6rgoZfZ6BMjTj/9S9hNN7EQoV05qUo="
|
||||
},
|
||||
"contactId": 1,
|
||||
"verified": true
|
||||
},
|
||||
"name": "ContactAddedRemotelyEvent",
|
||||
"type": "event"
|
||||
}
|
||||
```
|
||||
|
||||
### A pending contact changed its state
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"pendingContactId":"YqKjsczCuxScXohb5+RAYtFEwK71icoB4ldztV2gh7M=",
|
||||
"state":"waiting_for_connection"
|
||||
},
|
||||
"name": "PendingContactStateChangedEvent",
|
||||
"type": "event"
|
||||
}
|
||||
```
|
||||
|
||||
For a list of valid states, please see the section on adding contacts above.
|
||||
|
||||
### A pending contact was removed
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"pendingContactId": "YqKjsczCuxScXohb5+RAYtFEwK71icoB4ldztV2gh7M="
|
||||
},
|
||||
"name": "PendingContactRemovedEvent",
|
||||
"type": "event"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -5,8 +5,14 @@ import io.javalin.Context
|
||||
import io.javalin.NotFoundResponse
|
||||
import org.briarproject.bramble.api.contact.ContactManager
|
||||
import org.briarproject.bramble.api.contact.PendingContactId
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException
|
||||
import org.briarproject.bramble.api.db.NoSuchPendingContactException
|
||||
import org.briarproject.bramble.api.event.Event
|
||||
import org.briarproject.bramble.api.event.EventListener
|
||||
import org.briarproject.briar.headless.event.WebSocketController
|
||||
import org.briarproject.briar.headless.getContactIdFromPathParam
|
||||
import org.briarproject.briar.headless.getFromJson
|
||||
import org.briarproject.briar.headless.json.JsonDict
|
||||
@@ -16,12 +22,33 @@ import javax.annotation.concurrent.Immutable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
internal const val EVENT_CONTACT_ADDED_REMOTELY = "ContactAddedRemotelyEvent"
|
||||
internal const val EVENT_PENDING_CONTACT_STATE_CHANGED = "PendingContactStateChangedEvent"
|
||||
internal const val EVENT_PENDING_CONTACT_REMOVED = "PendingContactRemovedEvent"
|
||||
|
||||
@Immutable
|
||||
@Singleton
|
||||
internal class ContactControllerImpl
|
||||
@Inject
|
||||
constructor(private val contactManager: ContactManager, private val objectMapper: ObjectMapper) :
|
||||
ContactController {
|
||||
constructor(
|
||||
private val contactManager: ContactManager,
|
||||
private val objectMapper: ObjectMapper,
|
||||
private val webSocket: WebSocketController
|
||||
) : ContactController, EventListener {
|
||||
|
||||
override fun eventOccurred(e: Event) = when (e) {
|
||||
is ContactAddedRemotelyEvent -> {
|
||||
webSocket.sendEvent(EVENT_CONTACT_ADDED_REMOTELY, e.output())
|
||||
}
|
||||
is PendingContactStateChangedEvent -> {
|
||||
webSocket.sendEvent(EVENT_PENDING_CONTACT_STATE_CHANGED, e.output())
|
||||
}
|
||||
is PendingContactRemovedEvent -> {
|
||||
webSocket.sendEvent(EVENT_PENDING_CONTACT_REMOVED, e.output())
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun list(ctx: Context): Context {
|
||||
val contacts = contactManager.contacts.map { contact ->
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.briarproject.briar.headless.contact
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.briarproject.bramble.api.event.EventBus
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@@ -9,7 +10,11 @@ class HeadlessContactModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun provideContactController(contactController: ContactControllerImpl): ContactController {
|
||||
internal fun provideContactController(
|
||||
eventBus: EventBus,
|
||||
contactController: ContactControllerImpl
|
||||
): ContactController {
|
||||
eventBus.addListener(contactController)
|
||||
return contactController
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.briar.headless.contact
|
||||
|
||||
import org.briarproject.bramble.api.contact.Contact
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent
|
||||
import org.briarproject.bramble.identity.output
|
||||
import org.briarproject.briar.headless.json.JsonDict
|
||||
|
||||
@@ -8,4 +9,6 @@ internal fun Contact.output() = JsonDict(
|
||||
"contactId" to id.int,
|
||||
"author" to author.output(),
|
||||
"verified" to isVerified
|
||||
)
|
||||
)
|
||||
|
||||
internal fun ContactAddedRemotelyEvent.output() = contact.output()
|
||||
|
||||
@@ -1,18 +1,32 @@
|
||||
package org.briarproject.briar.headless.contact
|
||||
|
||||
import org.briarproject.bramble.api.contact.PendingContact
|
||||
import org.briarproject.bramble.api.contact.PendingContactState
|
||||
import org.briarproject.bramble.api.contact.PendingContactState.*
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent
|
||||
import org.briarproject.briar.headless.json.JsonDict
|
||||
|
||||
internal fun PendingContact.output() = JsonDict(
|
||||
"pendingContactId" to id.bytes,
|
||||
"alias" to alias,
|
||||
"state" to when(state) {
|
||||
WAITING_FOR_CONNECTION -> "waiting_for_connection"
|
||||
CONNECTED -> "connected"
|
||||
ADDING_CONTACT -> "adding_contact"
|
||||
FAILED -> "failed"
|
||||
else -> throw AssertionError()
|
||||
},
|
||||
"state" to state.output(),
|
||||
"timestamp" to timestamp
|
||||
)
|
||||
)
|
||||
|
||||
internal fun PendingContactState.output() = when(this) {
|
||||
WAITING_FOR_CONNECTION -> "waiting_for_connection"
|
||||
CONNECTED -> "connected"
|
||||
ADDING_CONTACT -> "adding_contact"
|
||||
FAILED -> "failed"
|
||||
else -> throw AssertionError()
|
||||
}
|
||||
|
||||
internal fun PendingContactStateChangedEvent.output() = JsonDict(
|
||||
"pendingContactId" to id.bytes,
|
||||
"state" to pendingContactState.output()
|
||||
)
|
||||
|
||||
internal fun PendingContactRemovedEvent.output() = JsonDict(
|
||||
"pendingContactId" to id.bytes
|
||||
)
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.sync.Message
|
||||
import org.briarproject.bramble.api.system.Clock
|
||||
import org.briarproject.bramble.test.TestUtils.*
|
||||
import org.briarproject.bramble.util.StringUtils.getRandomString
|
||||
import org.briarproject.briar.headless.event.WebSocketController
|
||||
import org.skyscreamer.jsonassert.JSONAssert.assertEquals
|
||||
import org.skyscreamer.jsonassert.JSONCompareMode.STRICT
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
@@ -26,6 +27,8 @@ abstract class ControllerTest {
|
||||
protected val clock = mockk<Clock>()
|
||||
protected val ctx = mockk<Context>()
|
||||
|
||||
protected val webSocketController = mockk<WebSocketController>()
|
||||
|
||||
private val request = mockk<HttpServletRequest>(relaxed = true)
|
||||
private val response = mockk<HttpServletResponse>(relaxed = true)
|
||||
private val outputCtx = ContextUtil.init(request, response)
|
||||
|
||||
@@ -5,9 +5,14 @@ import io.javalin.json.JavalinJson.toJson
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.runs
|
||||
import org.briarproject.bramble.api.contact.Contact
|
||||
import org.briarproject.bramble.api.contact.ContactId
|
||||
import org.briarproject.bramble.api.contact.PendingContactId
|
||||
import org.briarproject.bramble.api.contact.PendingContactState.FAILED
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException
|
||||
import org.briarproject.bramble.api.db.NoSuchPendingContactException
|
||||
import org.briarproject.bramble.identity.output
|
||||
@@ -20,9 +25,11 @@ import org.junit.jupiter.api.Test
|
||||
|
||||
internal class ContactControllerTest : ControllerTest() {
|
||||
|
||||
private val controller = ContactControllerImpl(contactManager, objectMapper)
|
||||
private val pendingContact = getPendingContact()
|
||||
|
||||
private val controller =
|
||||
ContactControllerImpl(contactManager, objectMapper, webSocketController)
|
||||
|
||||
@Test
|
||||
fun testEmptyContactList() {
|
||||
every { contactManager.contacts } returns emptyList<Contact>()
|
||||
@@ -134,6 +141,48 @@ internal class ContactControllerTest : ControllerTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testContactAddedRemotelyEvent() {
|
||||
val event = ContactAddedRemotelyEvent(contact)
|
||||
|
||||
every {
|
||||
webSocketController.sendEvent(
|
||||
EVENT_CONTACT_ADDED_REMOTELY,
|
||||
event.output()
|
||||
)
|
||||
} just runs
|
||||
|
||||
controller.eventOccurred(event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPendingContactStateChangedEvent() {
|
||||
val event = PendingContactStateChangedEvent(pendingContact.id, FAILED)
|
||||
|
||||
every {
|
||||
webSocketController.sendEvent(
|
||||
EVENT_PENDING_CONTACT_STATE_CHANGED,
|
||||
event.output()
|
||||
)
|
||||
} just runs
|
||||
|
||||
controller.eventOccurred(event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPendingContactRemovedEvent() {
|
||||
val event = PendingContactRemovedEvent(pendingContact.id)
|
||||
|
||||
every {
|
||||
webSocketController.sendEvent(
|
||||
EVENT_PENDING_CONTACT_REMOVED,
|
||||
event.output()
|
||||
)
|
||||
} just runs
|
||||
|
||||
controller.eventOccurred(event)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOutputContact() {
|
||||
val json = """
|
||||
@@ -159,6 +208,12 @@ internal class ContactControllerTest : ControllerTest() {
|
||||
assertJsonEquals(json, author.output())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOutputContactAddedRemotelyEvent() {
|
||||
val event = ContactAddedRemotelyEvent(contact)
|
||||
assertJsonEquals(toJson(contact.output()), event.output())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOutputPendingContact() {
|
||||
val json = """
|
||||
@@ -172,4 +227,27 @@ internal class ContactControllerTest : ControllerTest() {
|
||||
assertJsonEquals(json, pendingContact.output())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOutputPendingContactStateChangedEvent() {
|
||||
val event = PendingContactStateChangedEvent(pendingContact.id, FAILED)
|
||||
val json = """
|
||||
{
|
||||
"pendingContactId": ${toJson(pendingContact.id.bytes)},
|
||||
"state": "failed"
|
||||
}
|
||||
"""
|
||||
assertJsonEquals(json, event.output())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOutputPendingContactRemovedEvent() {
|
||||
val event = PendingContactRemovedEvent(pendingContact.id)
|
||||
val json = """
|
||||
{
|
||||
"pendingContactId": ${toJson(pendingContact.id.bytes)}
|
||||
}
|
||||
"""
|
||||
assertJsonEquals(json, event.output())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.briarproject.briar.api.messaging.PrivateMessageFactory
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader
|
||||
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent
|
||||
import org.briarproject.briar.headless.ControllerTest
|
||||
import org.briarproject.briar.headless.event.WebSocketController
|
||||
import org.briarproject.briar.headless.event.output
|
||||
import org.briarproject.briar.headless.json.JsonDict
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
@@ -35,7 +34,6 @@ internal class MessagingControllerImplTest : ControllerTest() {
|
||||
private val messagingManager = mockk<MessagingManager>()
|
||||
private val conversationManager = mockk<ConversationManager>()
|
||||
private val privateMessageFactory = mockk<PrivateMessageFactory>()
|
||||
private val webSocketController = mockk<WebSocketController>()
|
||||
private val dbExecutor = ImmediateExecutor()
|
||||
|
||||
private val controller = MessagingControllerImpl(
|
||||
|
||||
Reference in New Issue
Block a user