Skip to content

Commit

Permalink
[CHAT-4902] feat: add chat room skeleton and default implementations …
Browse files Browse the repository at this point in the history
…for main classes

In this PR most of the methods in the default implementations throws exceptions. We focused on happy path getting client, creating room, attaching to the room (without any corner cases)
  • Loading branch information
ttypic committed Sep 9, 2024
1 parent 7c0ec73 commit 69d4830
Show file tree
Hide file tree
Showing 14 changed files with 366 additions and 10 deletions.
10 changes: 3 additions & 7 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.kotlin) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.build.config) apply false
}

dependencies {
Expand Down
9 changes: 9 additions & 0 deletions chat-android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.android.kotlin)
alias(libs.plugins.build.config)
}

val version = libs.versions.ably.chat.get()

android {
namespace = "com.ably.chat"
compileSdk = 34
Expand Down Expand Up @@ -33,6 +36,12 @@ android {
}
}

buildConfig {
packageName("com.ably.chat")
useKotlinOutput { internalVisibility = true }
buildConfigField("APP_VERSION", provider { "\"${version}\"" })
}

dependencies {
api(libs.ably.android)
implementation(libs.gson)
Expand Down
25 changes: 24 additions & 1 deletion chat-android/src/main/java/com/ably/chat/ChatClient.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
@file:Suppress("StringLiteralDuplication", "NotImplementedDeclaration")

package com.ably.chat

import io.ably.lib.realtime.AblyRealtime
import io.ably.lib.types.ClientOptions

typealias RealtimeClient = AblyRealtime

Expand Down Expand Up @@ -35,3 +36,25 @@ interface ChatClient {
*/
val clientOptions: ClientOptions
}

fun ChatClient(realtimeClient: RealtimeClient, clientOptions: ClientOptions): ChatClient = DefaultChatClient(realtimeClient, clientOptions)

internal class DefaultChatClient(
override val realtime: RealtimeClient,
override val clientOptions: ClientOptions,
) : ChatClient {

private val chatApi = ChatApi(realtime, clientId)

override val rooms: Rooms = DefaultRooms(
realtimeClient = realtime,
chatApi = chatApi,
clientOptions = clientOptions,
)

override val connection: Connection
get() = TODO("Not yet implemented")

override val clientId: String
get() = realtime.auth.clientId
}
39 changes: 39 additions & 0 deletions chat-android/src/main/java/com/ably/chat/Messages.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("StringLiteralDuplication", "NotImplementedDeclaration")

package com.ably.chat

import io.ably.lib.realtime.Channel
Expand Down Expand Up @@ -173,3 +175,40 @@ data class SendMessageParams(
*/
val headers: MessageHeaders? = null,
)

class DefaultMessages(
private val roomId: String,
private val realtimeClient: RealtimeClient,
private val chatApi: ChatApi,
) : Messages {

/**
* the channel name for the chat messages channel.
*/
private val messagesChannelName = "$roomId::\$chat::\$chatMessages"

override val channel: Channel
get() = realtimeClient.channels.get(messagesChannelName, ChatChannelOptions())

override fun subscribe(listener: Messages.Listener) {
TODO("Not yet implemented")
}

override fun unsubscribe(listener: Messages.Listener) {
TODO("Not yet implemented")
}

override suspend fun get(options: QueryOptions): PaginatedResult<Message> {
TODO("Not yet implemented")
}

override suspend fun send(params: SendMessageParams): Message = chatApi.sendMessage(roomId, params)

override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) {
TODO("Not yet implemented")
}

override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) {
TODO("Not yet implemented")
}
}
29 changes: 29 additions & 0 deletions chat-android/src/main/java/com/ably/chat/Occupancy.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("StringLiteralDuplication", "NotImplementedDeclaration")

package com.ably.chat

import io.ably.lib.realtime.Channel
Expand Down Expand Up @@ -63,3 +65,30 @@ data class OccupancyEvent(
*/
val presenceMembers: Int,
)

internal class DefaultOccupancy(
private val messages: Messages,
) : Occupancy {
override val channel: Channel
get() = messages.channel

override fun subscribe(listener: Occupancy.Listener) {
TODO("Not yet implemented")
}

override fun unsubscribe(listener: Occupancy.Listener) {
TODO("Not yet implemented")
}

override suspend fun get(): OccupancyEvent {
TODO("Not yet implemented")
}

override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) {
TODO("Not yet implemented")
}

override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) {
TODO("Not yet implemented")
}
}
46 changes: 46 additions & 0 deletions chat-android/src/main/java/com/ably/chat/Presence.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("StringLiteralDuplication", "NotImplementedDeclaration")

package com.ably.chat

import android.text.PrecomputedText.Params
Expand Down Expand Up @@ -132,3 +134,47 @@ data class PresenceEvent(
*/
val data: PresenceData,
)

internal class DefaultPresence(
private val messages: Messages,
) : Presence {

override val channel: Channel
get() = messages.channel

override suspend fun get(params: List<Params>): List<PresenceMember> {
TODO("Not yet implemented")
}

override suspend fun isUserPresent(clientId: String): Boolean {
TODO("Not yet implemented")
}

override suspend fun enter(data: PresenceData?) {
TODO("Not yet implemented")
}

override suspend fun update(data: PresenceData?) {
TODO("Not yet implemented")
}

override suspend fun leave(data: PresenceData?) {
TODO("Not yet implemented")
}

override fun subscribe(listener: Presence.Listener) {
TODO("Not yet implemented")
}

override fun unsubscribe(listener: Presence.Listener) {
TODO("Not yet implemented")
}

override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) {
TODO("Not yet implemented")
}

override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) {
TODO("Not yet implemented")
}
}
51 changes: 51 additions & 0 deletions chat-android/src/main/java/com/ably/chat/Room.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("StringLiteralDuplication", "NotImplementedDeclaration")

package com.ably.chat

/**
Expand Down Expand Up @@ -80,3 +82,52 @@ interface Room {
*/
suspend fun detach()
}

internal class DefaultRoom(
override val roomId: String,
override val options: RoomOptions,
realtimeClient: RealtimeClient,
chatApi: ChatApi,
) : Room {

override val messages: Messages = DefaultMessages(
roomId = roomId,
realtimeClient = realtimeClient,
chatApi = chatApi,
)

override val presence: Presence = DefaultPresence(
messages = messages,
)

override val reactions: RoomReactions = DefaultRoomReactions(
roomId = roomId,
realtimeClient = realtimeClient,
)

override val typing: Typing = DefaultTyping(
roomId = roomId,
realtimeClient = realtimeClient,
)

override val occupancy: Occupancy = DefaultOccupancy(
messages = messages,
)

override val status: RoomStatus
get() {
TODO("Not yet implemented")
}

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

override suspend fun detach() {
messages.channel.detachCoroutine()
typing.channel.detachCoroutine()
reactions.channel.detachCoroutine()
}
}
32 changes: 32 additions & 0 deletions chat-android/src/main/java/com/ably/chat/RoomReactions.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("StringLiteralDuplication", "NotImplementedDeclaration")

package com.ably.chat

import io.ably.lib.realtime.Channel
Expand Down Expand Up @@ -100,3 +102,33 @@ data class SendReactionParams(
*/
val headers: ReactionHeaders? = null,
)

internal class DefaultRoomReactions(
roomId: String,
private val realtimeClient: RealtimeClient,
) : RoomReactions {
private val roomReactionsChannelName = "$roomId::\$chat::\$reactions"

override val channel: Channel
get() = realtimeClient.channels.get(roomReactionsChannelName, ChatChannelOptions())

override suspend fun send(params: SendReactionParams) {
TODO("Not yet implemented")
}

override fun subscribe(listener: RoomReactions.Listener) {
TODO("Not yet implemented")
}

override fun unsubscribe(listener: RoomReactions.Listener) {
TODO("Not yet implemented")
}

override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) {
TODO("Not yet implemented")
}

override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) {
TODO("Not yet implemented")
}
}
41 changes: 41 additions & 0 deletions chat-android/src/main/java/com/ably/chat/Rooms.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.ably.chat

import io.ably.lib.types.AblyException
import io.ably.lib.types.ErrorInfo

/**
* Manages the lifecycle of chat rooms.
*/
Expand Down Expand Up @@ -35,3 +38,41 @@ interface Rooms {
*/
suspend fun release(roomId: String)
}

/**
* Manages the chat rooms.
*/
internal class DefaultRooms(
private val realtimeClient: RealtimeClient,
private val chatApi: ChatApi,
override val clientOptions: ClientOptions,
) : Rooms {
private val roomIdToRoom: MutableMap<String, Room> = mutableMapOf()

override fun get(roomId: String, options: RoomOptions): Room {
return synchronized(this) {
val room = roomIdToRoom.getOrPut(roomId) {
DefaultRoom(
roomId = roomId,
options = options,
realtimeClient = realtimeClient,
chatApi = chatApi,
)
}

if (room.options != options) {
throw AblyException.fromErrorInfo(
ErrorInfo("Room already exists with different options", HttpStatusCodes.BadRequest, ErrorCodes.BadRequest),
)
}

room
}
}

override suspend fun release(roomId: String) {
synchronized(this) {
roomIdToRoom.remove(roomId)
}
}
}
Loading

0 comments on commit 69d4830

Please sign in to comment.