Skip to content

Commit

Permalink
Parse EventType directly and turn it non-nullable
Browse files Browse the repository at this point in the history
  • Loading branch information
PattaFeuFeu committed Dec 17, 2023
1 parent a66b4f0 commit 0525c33
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 147 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import okio.IOException
import org.junit.jupiter.api.Test
import social.bigbone.api.entity.streaming.MastodonApiEvent
import social.bigbone.api.entity.streaming.ParsedStreamEvent
import social.bigbone.api.entity.streaming.StreamType
import social.bigbone.api.entity.streaming.TechnicalEvent
import social.bigbone.api.entity.streaming.WebSocketEvent
import social.bigbone.rx.testtool.MockClient
Expand All @@ -32,11 +33,26 @@ class RxStreamingMethodsTest {
fun `Given websocket with 6 events lined up, when streaming federated public timeline, then expect emissions and no errors`() {
val mockedEvents: List<WebSocketEvent> = listOf(
TechnicalEvent.Open,
MastodonApiEvent.StreamEvent(ParsedStreamEvent.FiltersChanged),
MastodonApiEvent.StreamEvent(ParsedStreamEvent.StatusDeleted(deletedStatusId = "12345")),
MastodonApiEvent.StreamEvent(ParsedStreamEvent.AnnouncementDeleted(deletedAnnouncementId = "54321")),
MastodonApiEvent.StreamEvent(ParsedStreamEvent.FiltersChanged),
MastodonApiEvent.StreamEvent(ParsedStreamEvent.StatusCreated(createdStatus = mockk()))
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.FiltersChanged,
listOf(StreamType.PUBLIC)
),
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.StatusCreated(mockk()),
listOf(StreamType.PUBLIC)
),
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.StatusDeleted(deletedStatusId = "12345"),
listOf(StreamType.PUBLIC)
),
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.AnnouncementDeleted(deletedAnnouncementId = "54321"),
listOf(StreamType.PUBLIC)
),
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.StatusCreated(createdStatus = mockk()),
listOf(StreamType.PUBLIC)
)
)
val client = MockClient.mockWebSocket(events = mockedEvents)
val streamingMethods = RxStreamingMethods(client)
Expand Down
4 changes: 2 additions & 2 deletions bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ private constructor(
try {
val rawEvent: RawStreamEvent = JSON_SERIALIZER.decodeFromString<RawStreamEvent>(text)
val streamEvent = rawEvent.toStreamEvent()
callback.onEvent(StreamEvent(event = streamEvent))
callback.onEvent(StreamEvent(event = streamEvent, streamTypes = rawEvent.stream))
} catch (e: IllegalArgumentException) {
callback.onEvent(GenericMessage(text))
}
Expand All @@ -597,7 +597,7 @@ private constructor(
try {
val rawEvent = JSON_SERIALIZER.decodeFromString<RawStreamEvent>(bytesAsString)
val streamEvent = rawEvent.toStreamEvent()
callback.onEvent(StreamEvent(event = streamEvent))
callback.onEvent(StreamEvent(event = streamEvent, streamTypes = rawEvent.stream))
} catch (e: IllegalArgumentException) {
callback.onEvent(GenericMessage(bytesAsString))
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,9 @@ import social.bigbone.api.entity.Announcement
import social.bigbone.api.entity.Conversation
import social.bigbone.api.entity.Notification
import social.bigbone.api.entity.Status
import social.bigbone.api.entity.streaming.EventType.ANNOUNCEMENT
import social.bigbone.api.entity.streaming.EventType.ANNOUNCEMENT_DELETE
import social.bigbone.api.entity.streaming.EventType.ANNOUNCEMENT_REACTION
import social.bigbone.api.entity.streaming.EventType.CONVERSATION
import social.bigbone.api.entity.streaming.EventType.DELETE
import social.bigbone.api.entity.streaming.EventType.ENCRYPTED_MESSAGE
import social.bigbone.api.entity.streaming.EventType.FILTERS_CHANGED
import social.bigbone.api.entity.streaming.EventType.NOTIFICATION
import social.bigbone.api.entity.streaming.EventType.STATUS_UPDATE
import social.bigbone.api.entity.streaming.EventType.UPDATE

/**
* Stream events emitted by the Mastodon API websocket stream for each [EventType] that can potentially occur.
* Stream events emitted by the Mastodon API websocket stream for each event type that can occur.
* This is the parsed variant of the [RawStreamEvent.eventType] and [RawStreamEvent.payload]
* turned into easily usable data classes and objects for type-specific consumption.
*/
Expand Down Expand Up @@ -86,52 +76,57 @@ sealed interface ParsedStreamEvent {
*/
data object EncryptedMessageReceived : ParsedStreamEvent

/**
* Type received via the Mastodon API that is not (yet) available in BigBone.
*/
data class UnknownType(val eventType: String, val payload: String?) : ParsedStreamEvent

companion object {
internal fun RawStreamEvent.toStreamEvent(json: Json = JSON_SERIALIZER): ParsedStreamEvent? {
internal fun RawStreamEvent.toStreamEvent(json: Json = JSON_SERIALIZER): ParsedStreamEvent {
return when (eventType) {
UPDATE -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustnt be." }
"update" -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustn't be." }
StatusCreated(createdStatus = json.decodeFromString(payload))
}

DELETE -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustnt be." }
"delete" -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustn't be." }
StatusDeleted(deletedStatusId = payload)
}

NOTIFICATION -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustnt be." }
"notification" -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustn't be." }
NewNotification(newNotification = json.decodeFromString(payload))
}

CONVERSATION -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustnt be." }
"conversation" -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustn't be." }
ConversationUpdated(updatedConversation = json.decodeFromString(payload))
}

ANNOUNCEMENT -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustnt be." }
"announcement" -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustn't be." }
AnnouncementPublished(publishedAnnouncement = json.decodeFromString(payload))
}

ANNOUNCEMENT_REACTION -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustnt be." }
"announcement.reaction" -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustn't be." }
AnnouncementReactionReceived(reactionPayload = json.decodeFromString(payload))
}

ANNOUNCEMENT_DELETE -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustnt be." }
"announcement.delete" -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustn't be." }
AnnouncementDeleted(deletedAnnouncementId = payload)
}

STATUS_UPDATE -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustnt be." }
"status.update" -> {
requireNotNull(payload) { "Payload was null for update $eventType but mustn't be." }
StatusEdited(editedStatus = json.decodeFromString(payload))
}

FILTERS_CHANGED -> FiltersChanged
ENCRYPTED_MESSAGE -> EncryptedMessageReceived
else -> null
"filters_changed" -> FiltersChanged
"encrypted_message" -> EncryptedMessageReceived
else -> UnknownType(eventType, payload)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
/**
* Raw streaming event constantly emitted by the streaming APIs.
* Can be parsed to a [ParsedStreamEvent] which then contains specific data classes and objects for the different
* [EventType]s that can occur here.
* [eventType]s that can occur here.
* @see <a href="https://docs.joinmastodon.org/methods/streaming/#events">Mastodon streaming#events entity docs</a>
*/
@Serializable
Expand All @@ -19,14 +19,13 @@ internal data class RawStreamEvent(
val stream: List<StreamType>? = null,

/**
* Type of event, such as status update, represented by [EventType].
* Type of event, such as "status.update".
*/
@SerialName("event")
val eventType: EventType? = null,
val eventType: String,

/**
* Payload sent with the event. Content depends on [eventType] type.
* See [EventType] for documentation about possible payloads.
*/
@SerialName("payload")
val payload: String? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kotlinx.serialization.Serializable
* @see <a href="https://docs.joinmastodon.org/methods/streaming/#events">Mastodon streaming#events entities</a>
*/
@Serializable
internal enum class StreamType {
enum class StreamType {

/**
* All public posts known to the server.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ sealed interface MastodonApiEvent : WebSocketEvent {
/**
* An event from the Mastodon API has been received via the websocket.
*
* @property event The parsed stream event. May be null if we got an [EventType] we don’t know yet.
* @property event The parsed stream event. May be [ParsedStreamEvent.UnknownType] if it's unknown to BigBone.
* @property streamTypes The [StreamType]s received as part of the event.
*/
data class StreamEvent(val event: ParsedStreamEvent?) : MastodonApiEvent
data class StreamEvent(val event: ParsedStreamEvent, val streamTypes: List<StreamType>?) : MastodonApiEvent

/**
* A message received via the websocket that could not be parsed to a [ParsedStreamEvent].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,26 @@ class StreamingMethodsTest {
fun `Given websocket with 6 events lined up, when streaming federated public timeline, then expect emissions and no errors`() {
val sentEvents = listOf(
TechnicalEvent.Open,
MastodonApiEvent.StreamEvent(ParsedStreamEvent.FiltersChanged),
MastodonApiEvent.StreamEvent(ParsedStreamEvent.StatusCreated(mockk())),
MastodonApiEvent.StreamEvent(ParsedStreamEvent.StatusDeleted(deletedStatusId = "12345")),
MastodonApiEvent.StreamEvent(ParsedStreamEvent.AnnouncementDeleted(deletedAnnouncementId = "54321")),
MastodonApiEvent.StreamEvent(ParsedStreamEvent.StatusCreated(createdStatus = mockk()))
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.FiltersChanged,
listOf(StreamType.PUBLIC)
),
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.StatusCreated(mockk()),
listOf(StreamType.PUBLIC)
),
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.StatusDeleted(deletedStatusId = "12345"),
listOf(StreamType.PUBLIC)
),
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.AnnouncementDeleted(deletedAnnouncementId = "54321"),
listOf(StreamType.PUBLIC)
),
MastodonApiEvent.StreamEvent(
ParsedStreamEvent.StatusCreated(createdStatus = mockk()),
listOf(StreamType.PUBLIC)
)
)
val client = MockClient.mockWebSocket(sentEvents)
val streamingMethods = StreamingMethods(client)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ object StreamFederatedPublicTimeline {
is TechnicalEvent -> println("Technical event: $it")
is MastodonApiEvent -> when (it) {
is GenericMessage -> println("Generic message: $it")
is StreamEvent -> println("API event: ${it.event!!::class.java.simpleName}")
is StreamEvent -> println("API event: ${it.event::class.java.simpleName}")
}
}
}
Expand Down

0 comments on commit 0525c33

Please sign in to comment.