Verified Commit 3770a9f2 authored by Torsten Grote's avatar Torsten Grote
Browse files

[headless] make events related to adding contacts available via websocket

parent c6211be4
......@@ -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
\ No newline at end of file
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
}
......
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
)
\ No newline at end of file
)
internal fun ContactAddedRemotelyEvent.output() = contact.output()
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
)
\ No newline at end of file
)
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(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment