Skip to content

Commit

Permalink
[ECO-5096][CHA-RC2] Initialise room based on provided RoomOptions
Browse files Browse the repository at this point in the history
1. Refactored room, added init method to initialize room features based on
provided roomOptions
2. Added extension 'RoomOptions.validateRoomOptions' to validate given
RoomOptions
3. Added unit test 'ConfigureRoomOptionsTest' to make sure RoomOptions are
well validated, fixed other unit/sandbox tests based on logger.
4. Updated detekt.yml, allowed logger to be unused.
  • Loading branch information
sacOO7 committed Nov 26, 2024
1 parent 2717cdc commit a854f55
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 49 deletions.
1 change: 1 addition & 0 deletions chat-android/src/main/java/com/ably/chat/Messages.kt
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ internal class DefaultMessages(
private val roomId: String,
realtimeChannels: AblyRealtime.Channels,
private val chatApi: ChatApi,
logger: Logger,
) : Messages {

private var listeners: Map<Messages.Listener, DeferredValue<String>> = emptyMap()
Expand Down
1 change: 1 addition & 0 deletions chat-android/src/main/java/com/ably/chat/Presence.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ internal class DefaultPresence(
private val clientId: String,
override val channel: Channel,
private val presence: PubSubPresence,
logger: Logger,
) : Presence {

override suspend fun get(waitForSync: Boolean, clientId: String?, connectionId: String?): List<PresenceMember> {
Expand Down
134 changes: 90 additions & 44 deletions chat-android/src/main/java/com/ably/chat/Room.kt
Original file line number Diff line number Diff line change
Expand Up @@ -109,80 +109,126 @@ internal class DefaultRoom(
private val realtimeClient: RealtimeClient,
chatApi: ChatApi,
clientId: String,
private val logger: Logger,
logger: Logger,
) : Room {
private val roomLogger = logger.withContext("Room", mapOf("roomId" to roomId))

private val _messages = DefaultMessages(
override val messages = DefaultMessages(
roomId = roomId,
realtimeChannels = realtimeClient.channels,
chatApi = chatApi,
logger = roomLogger.withContext(tag = "Messages"),
)

private val _typing: DefaultTyping = DefaultTyping(
roomId = roomId,
realtimeClient = realtimeClient,
options = options.typing,
clientId = clientId,
logger = logger.withContext(tag = "Typing"),
)

private val _occupancy = DefaultOccupancy(
roomId = roomId,
realtimeChannels = realtimeClient.channels,
chatApi = chatApi,
logger = logger.withContext(tag = "Occupancy"),
)

override val messages: Messages
get() = _messages

private var _presence: Presence? = null
override val presence: Presence
get() {
if (_presence == null) { // CHA-RC2b
throw ablyException("Presence is not enabled for this room", ErrorCode.BadRequest)
}
return _presence as Presence
}

private var _reactions: RoomReactions? = null
override val reactions: RoomReactions
get() {
if (_reactions == null) { // CHA-RC2b
throw ablyException("Reactions are not enabled for this room", ErrorCode.BadRequest)
}
return _reactions as RoomReactions
}

private var _typing: Typing? = null
override val typing: Typing
get() = _typing

get() {
if (_typing == null) { // CHA-RC2b
throw ablyException("Typing is not enabled for this room", ErrorCode.BadRequest)
}
return _typing as Typing
}

private var _occupancy: Occupancy? = null
override val occupancy: Occupancy
get() = _occupancy
get() {
if (_occupancy == null) { // CHA-RC2b
throw ablyException("Occupancy is not enabled for this room", ErrorCode.BadRequest)
}
return _occupancy as Occupancy
}

override val presence: Presence = DefaultPresence(
channel = messages.channel,
clientId = clientId,
presence = messages.channel.presence,
)

override val reactions: RoomReactions = DefaultRoomReactions(
roomId = roomId,
clientId = clientId,
realtimeChannels = realtimeClient.channels,
)

private val statusLifecycle = DefaultRoomLifecycle(logger)
private val statusLifecycle = DefaultRoomLifecycle(roomLogger)

override val status: RoomStatus
get() = statusLifecycle.status

override val error: ErrorInfo?
get() = statusLifecycle.error

override fun onStatusChange(listener: RoomLifecycle.Listener): Subscription = statusLifecycle.onChange(listener)
init {
options.validateRoomOptions() // CHA-RC2a

options.presence?.let {
val presenceContributor = DefaultPresence(
clientId = clientId,
channel = messages.channel,
presence = messages.channel.presence,
logger = roomLogger.withContext(tag = "Presence"),
)
_presence = presenceContributor
}

options.typing?.let {
val typingContributor = DefaultTyping(
roomId = roomId,
realtimeClient = realtimeClient,
clientId = clientId,
options = options.typing,
logger = roomLogger.withContext(tag = "Typing"),
)
_typing = typingContributor
}

options.reactions?.let {
val reactionsContributor = DefaultRoomReactions(
roomId = roomId,
clientId = clientId,
realtimeChannels = realtimeClient.channels,
logger = roomLogger.withContext(tag = "Reactions"),
)
_reactions = reactionsContributor
}

options.occupancy?.let {
val occupancyContributor = DefaultOccupancy(
roomId = roomId,
realtimeChannels = realtimeClient.channels,
chatApi = chatApi,
logger = roomLogger.withContext(tag = "Occupancy"),
)
_occupancy = occupancyContributor
}
}

override fun onStatusChange(listener: RoomLifecycle.Listener): Subscription =
statusLifecycle.onChange(listener)

override fun offAllStatusChange() {
statusLifecycle.offAll()
}

override suspend fun attach() {
messages.channel.attachCoroutine()
typing.channel.attachCoroutine()
reactions.channel.attachCoroutine()
_typing?.channel?.attachCoroutine()
_reactions?.channel?.attachCoroutine()
}

override suspend fun detach() {
messages.channel.detachCoroutine()
typing.channel.detachCoroutine()
reactions.channel.detachCoroutine()
_typing?.channel?.detachCoroutine()
_reactions?.channel?.detachCoroutine()
}

suspend fun release() {
_messages.release()
_typing.release()
_occupancy.release()
messages.release()
}
}
16 changes: 14 additions & 2 deletions chat-android/src/main/java/com/ably/chat/RoomOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ data class TypingOptions(
/**
* The timeout for typing events in milliseconds. If typing.start() is not called for this amount of time, a stop
* typing event will be fired, resulting in the user being removed from the currently typing set.
* @defaultValue 10000
* @defaultValue 5000
*/
val timeoutMs: Long = 10_000,
val timeoutMs: Long = 5000,
)

/**
Expand All @@ -84,3 +84,15 @@ object RoomReactionsOptions
* Represents the occupancy options for a chat room.
*/
object OccupancyOptions

/**
* Throws AblyException for invalid room configuration.
* Spec: CHA-RC2a
*/
fun RoomOptions.validateRoomOptions() {
typing?.let {
if (typing.timeoutMs <= 0) {
throw ablyException("Typing timeout must be greater than 0", ErrorCode.InvalidRequestBody)
}
}
}
1 change: 1 addition & 0 deletions chat-android/src/main/java/com/ably/chat/RoomReactions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ internal class DefaultRoomReactions(
roomId: String,
private val clientId: String,
realtimeChannels: AblyRealtime.Channels,
logger: Logger,
) : RoomReactions {
// (CHA-ER1)
private val roomReactionsChannelName = "$roomId::\$chat::\$reactions"
Expand Down
3 changes: 3 additions & 0 deletions chat-android/src/test/java/com/ably/chat/MessagesTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ably.chat

import com.ably.chat.room.createMockLogger
import com.google.gson.JsonObject
import io.ably.lib.realtime.AblyRealtime.Channels
import io.ably.lib.realtime.Channel
Expand Down Expand Up @@ -30,6 +31,7 @@ class MessagesTest {
private val realtimeChannel = spyk<Channel>(buildRealtimeChannel())
private val chatApi = spyk(ChatApi(realtimeClient, "clientId", EmptyLogger(LogContext(tag = "TEST"))))
private lateinit var messages: DefaultMessages
private val logger = createMockLogger()

private val channelStateListenerSlot = slot<ChannelStateListener>()

Expand All @@ -45,6 +47,7 @@ class MessagesTest {
roomId = "room1",
realtimeChannels = realtimeChannels,
chatApi = chatApi,
logger,
)
}

Expand Down
3 changes: 3 additions & 0 deletions chat-android/src/test/java/com/ably/chat/PresenceTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ably.chat

import com.ably.chat.room.createMockLogger
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import io.ably.lib.realtime.Channel
Expand All @@ -20,13 +21,15 @@ class PresenceTest {
private val pubSubChannel = spyk<Channel>(buildRealtimeChannel("room1::\$chat::\$messages"))
private val pubSubPresence = mockk<PubSubPresence>(relaxed = true)
private lateinit var presence: DefaultPresence
private val logger = createMockLogger()

@Before
fun setUp() {
presence = DefaultPresence(
clientId = "client1",
channel = pubSubChannel,
presence = pubSubPresence,
logger,
)
}

Expand Down
4 changes: 4 additions & 0 deletions chat-android/src/test/java/com/ably/chat/RoomReactionsTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ably.chat

import com.ably.chat.room.createMockLogger
import com.google.gson.JsonObject
import io.ably.lib.realtime.AblyRealtime.Channels
import io.ably.lib.realtime.Channel
Expand All @@ -19,6 +20,7 @@ class RoomReactionsTest {
private val realtimeChannels = mockk<Channels>(relaxed = true)
private val realtimeChannel = spyk<Channel>(buildRealtimeChannel("room1::\$chat::\$reactions"))
private lateinit var roomReactions: DefaultRoomReactions
private val logger = createMockLogger()

@Before
fun setUp() {
Expand All @@ -35,6 +37,7 @@ class RoomReactionsTest {
roomId = "room1",
clientId = "client1",
realtimeChannels = realtimeChannels,
logger,
)
}

Expand All @@ -47,6 +50,7 @@ class RoomReactionsTest {
roomId = "foo",
clientId = "client1",
realtimeChannels = realtimeChannels,
logger,
)

assertEquals(
Expand Down
6 changes: 4 additions & 2 deletions chat-android/src/test/java/com/ably/chat/SandboxTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import org.junit.Test

class SandboxTest {

private val roomOptions = RoomOptions.default

@Test
fun `should return empty list of presence members if nobody is entered`() = runTest {
val chatClient = sandbox.createSandboxChatClient()
val room = chatClient.rooms.get(UUID.randomUUID().toString())
val room = chatClient.rooms.get(UUID.randomUUID().toString(), roomOptions)
room.attach()
val members = room.presence.get()
assertEquals(0, members.size)
Expand All @@ -21,7 +23,7 @@ class SandboxTest {
@Test
fun `should return yourself as presence member after you entered`() = runTest {
val chatClient = sandbox.createSandboxChatClient("sandbox-client")
val room = chatClient.rooms.get(UUID.randomUUID().toString())
val room = chatClient.rooms.get(UUID.randomUUID().toString(), roomOptions)
room.attach()
room.presence.enter()
val members = room.presence.get()
Expand Down
Loading

0 comments on commit a854f55

Please sign in to comment.