-
Notifications
You must be signed in to change notification settings - Fork 0
[CHA-RC1][ECO-5101] Implement Async Room Get + Release #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 22 commits
d5f5e82
9d21f69
878face
89df802
c6b2589
13ce9e4
b1c09b1
8c5e02b
a3d7bb4
bdccd57
dcc9538
a183715
f9586d0
e0d3621
d8f60f8
f3ef0f8
eaba999
ef38602
76e0b01
40d092c
d5bc58a
ae31f2b
c1a4504
9313999
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,12 +2,18 @@ | |||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
package com.ably.chat | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
import android.text.PrecomputedText.Params | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.types.ErrorInfo | ||||||||||||||||||||||||||||||||||||||||||||||
import com.google.gson.JsonElement | ||||||||||||||||||||||||||||||||||||||||||||||
import com.google.gson.JsonObject | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.realtime.Channel | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.realtime.Presence.GET_CLIENTID | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.realtime.Presence.GET_CONNECTIONID | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.realtime.Presence.GET_WAITFORSYNC | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.types.Param | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.types.PresenceMessage | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.realtime.Channel as AblyRealtimeChannel | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.realtime.Presence as PubSubPresence | ||||||||||||||||||||||||||||||||||||||||||||||
import io.ably.lib.realtime.Presence.PresenceListener as PubSubPresenceListener | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
typealias PresenceData = Any | ||||||||||||||||||||||||||||||||||||||||||||||
typealias PresenceData = JsonElement | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* This interface is used to interact with presence in a chat room: subscribing to presence events, | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -20,14 +26,15 @@ interface Presence : EmitsDiscontinuities { | |||||||||||||||||||||||||||||||||||||||||||||
* Get the underlying Ably realtime channel used for presence in this chat room. | ||||||||||||||||||||||||||||||||||||||||||||||
* @returns The realtime channel. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
val channel: AblyRealtimeChannel | ||||||||||||||||||||||||||||||||||||||||||||||
val channel: Channel | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* Method to get list of the current online users and returns the latest presence messages associated to it. | ||||||||||||||||||||||||||||||||||||||||||||||
* @param {Ably.RealtimePresenceParams} params - Parameters that control how the presence set is retrieved. | ||||||||||||||||||||||||||||||||||||||||||||||
* @returns {Promise<PresenceMessage[]>} or upon failure, the promise will be rejected with an [[Ably.ErrorInfo]] object which explains the error. | ||||||||||||||||||||||||||||||||||||||||||||||
* Method to get list of the current online users and returns the latest presence messages associated to it. | ||||||||||||||||||||||||||||||||||||||||||||||
* @param {Ably.RealtimePresenceParams} params - Parameters that control how the presence set is retrieved. | ||||||||||||||||||||||||||||||||||||||||||||||
* @throws {@link io.ably.lib.types.AblyException} object which explains the error. | ||||||||||||||||||||||||||||||||||||||||||||||
* @returns {List<PresenceMessage>} | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun get(params: List<Params>): List<PresenceMember> | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun get(waitForSync: Boolean = true, clientId: String? = null, connectionId: String? = null): List<PresenceMember> | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* Method to check if user with supplied clientId is online | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -39,23 +46,23 @@ interface Presence : EmitsDiscontinuities { | |||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* Method to join room presence, will emit an enter event to all subscribers. Repeat calls will trigger more enter events. | ||||||||||||||||||||||||||||||||||||||||||||||
* @param {PresenceData} data - The users data, a JSON serializable object that will be sent to all subscribers. | ||||||||||||||||||||||||||||||||||||||||||||||
* @returns {Promise<void>} or upon failure, the promise will be rejected with an {@link ErrorInfo} object which explains the error. | ||||||||||||||||||||||||||||||||||||||||||||||
* @throws {@link io.ably.lib.types.AblyException} object which explains the error. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun enter(data: PresenceData?) | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun enter(data: PresenceData? = null) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* Method to update room presence, will emit an update event to all subscribers. If the user is not present, it will be treated as a join event. | ||||||||||||||||||||||||||||||||||||||||||||||
* @param {PresenceData} data - The users data, a JSON serializable object that will be sent to all subscribers. | ||||||||||||||||||||||||||||||||||||||||||||||
* @returns {Promise<void>} or upon failure, the promise will be rejected with an {@link ErrorInfo} object which explains the error. | ||||||||||||||||||||||||||||||||||||||||||||||
* @throws {@link io.ably.lib.types.AblyException} object which explains the error. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun update(data: PresenceData?) | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun update(data: PresenceData? = null) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* Method to leave room presence, will emit a leave event to all subscribers. If the user is not present, it will be treated as a no-op. | ||||||||||||||||||||||||||||||||||||||||||||||
* @param {PresenceData} data - The users data, a JSON serializable object that will be sent to all subscribers. | ||||||||||||||||||||||||||||||||||||||||||||||
* @returns {Promise<void>} or upon failure, the promise will be rejected with an {@link ErrorInfo} object which explains the error. | ||||||||||||||||||||||||||||||||||||||||||||||
* @throws {@link io.ably.lib.types.AblyException} object which explains the error. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun leave(data: PresenceData?) | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun leave(data: PresenceData? = null) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* Subscribe the given listener to all presence events. | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -87,7 +94,7 @@ data class PresenceMember( | |||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* The data associated with the presence member. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
val data: PresenceData, | ||||||||||||||||||||||||||||||||||||||||||||||
val data: PresenceData?, | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* The current state of the presence member. | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -122,50 +129,83 @@ data class PresenceEvent( | |||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* The timestamp of the presence event. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
val timestamp: Int, | ||||||||||||||||||||||||||||||||||||||||||||||
val timestamp: Long, | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* The data associated with the presence event. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
val data: PresenceData, | ||||||||||||||||||||||||||||||||||||||||||||||
val data: PresenceData?, | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
internal class DefaultPresence( | ||||||||||||||||||||||||||||||||||||||||||||||
private val messages: Messages, | ||||||||||||||||||||||||||||||||||||||||||||||
) : Presence, ContributesToRoomLifecycleImpl(), ResolvedContributor { | ||||||||||||||||||||||||||||||||||||||||||||||
private val clientId: String, | ||||||||||||||||||||||||||||||||||||||||||||||
override val channel: Channel, | ||||||||||||||||||||||||||||||||||||||||||||||
private val presence: PubSubPresence, | ||||||||||||||||||||||||||||||||||||||||||||||
) : Presence, ContributesToRoomLifecycleImpl() { | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override val featureName = "presence" | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override val channel = messages.channel | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override val contributor: ContributesToRoomLifecycle = this | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override val attachmentErrorCode: ErrorCodes = ErrorCodes.PresenceAttachmentFailed | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override val detachmentErrorCode: ErrorCodes = ErrorCodes.PresenceDetachmentFailed | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override suspend fun get(params: List<Params>): List<PresenceMember> { | ||||||||||||||||||||||||||||||||||||||||||||||
TODO("Not yet implemented") | ||||||||||||||||||||||||||||||||||||||||||||||
suspend fun get(params: List<Param>): List<PresenceMember> { | ||||||||||||||||||||||||||||||||||||||||||||||
val usersOnPresence = presence.getCoroutine(params) | ||||||||||||||||||||||||||||||||||||||||||||||
return usersOnPresence.map { user -> | ||||||||||||||||||||||||||||||||||||||||||||||
PresenceMember( | ||||||||||||||||||||||||||||||||||||||||||||||
clientId = user.clientId, | ||||||||||||||||||||||||||||||||||||||||||||||
action = user.action, | ||||||||||||||||||||||||||||||||||||||||||||||
data = (user.data as? JsonObject)?.get("userCustomData"), | ||||||||||||||||||||||||||||||||||||||||||||||
updatedAt = user.timestamp, | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override suspend fun isUserPresent(clientId: String): Boolean { | ||||||||||||||||||||||||||||||||||||||||||||||
TODO("Not yet implemented") | ||||||||||||||||||||||||||||||||||||||||||||||
override suspend fun get(waitForSync: Boolean, clientId: String?, connectionId: String?): List<PresenceMember> { | ||||||||||||||||||||||||||||||||||||||||||||||
val params = buildList { | ||||||||||||||||||||||||||||||||||||||||||||||
if (waitForSync) add(Param(GET_WAITFORSYNC, true)) | ||||||||||||||||||||||||||||||||||||||||||||||
clientId?.let { add(Param(GET_CLIENTID, it)) } | ||||||||||||||||||||||||||||||||||||||||||||||
connectionId?.let { add(Param(GET_CONNECTIONID, it)) } | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
return get(params) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override suspend fun isUserPresent(clientId: String): Boolean = presence.getCoroutine(Param(GET_CLIENTID, clientId)).isNotEmpty() | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override suspend fun enter(data: PresenceData?) { | ||||||||||||||||||||||||||||||||||||||||||||||
TODO("Not yet implemented") | ||||||||||||||||||||||||||||||||||||||||||||||
presence.enterClientCoroutine(clientId, wrapInUserCustomData(data)) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override suspend fun update(data: PresenceData?) { | ||||||||||||||||||||||||||||||||||||||||||||||
TODO("Not yet implemented") | ||||||||||||||||||||||||||||||||||||||||||||||
presence.updateClientCoroutine(clientId, wrapInUserCustomData(data)) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override suspend fun leave(data: PresenceData?) { | ||||||||||||||||||||||||||||||||||||||||||||||
TODO("Not yet implemented") | ||||||||||||||||||||||||||||||||||||||||||||||
presence.leaveClientCoroutine(clientId, wrapInUserCustomData(data)) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override fun subscribe(listener: Presence.Listener): Subscription { | ||||||||||||||||||||||||||||||||||||||||||||||
TODO("Not yet implemented") | ||||||||||||||||||||||||||||||||||||||||||||||
val presenceListener = PubSubPresenceListener { | ||||||||||||||||||||||||||||||||||||||||||||||
val presenceEvent = PresenceEvent( | ||||||||||||||||||||||||||||||||||||||||||||||
action = it.action, | ||||||||||||||||||||||||||||||||||||||||||||||
clientId = it.clientId, | ||||||||||||||||||||||||||||||||||||||||||||||
timestamp = it.timestamp, | ||||||||||||||||||||||||||||||||||||||||||||||
data = (it.data as? JsonObject)?.get("userCustomData"), | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
listener.onEvent(presenceEvent) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+188
to
+196
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle potential nulls in In the Apply this diff to improve null safety: -val data = (it.data as? JsonObject)?.get("userCustomData")
+val data = if (it.data is JsonObject) {
+ (it.data as JsonObject).get("userCustomData")
+} else {
+ null
+} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
presence.subscribe(presenceListener) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
return Subscription { | ||||||||||||||||||||||||||||||||||||||||||||||
presence.unsubscribe(presenceListener) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
private fun wrapInUserCustomData(data: PresenceData?) = data?.let { | ||||||||||||||||||||||||||||||||||||||||||||||
JsonObject().apply { | ||||||||||||||||||||||||||||||||||||||||||||||
add("userCustomData", data) | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
override fun release() { | ||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure safe casting and data retrieval in
get
methodWhen mapping
PresenceMessage
instances toPresenceMember
, the linedata = (user.data as? JsonObject)?.get("userCustomData")
assumes thatuser.data
can be cast toJsonObject
. To prevent potentialClassCastException
s, ensure thatuser.data
is safely cast and handle cases where it might not be aJsonObject
.Apply this diff to enhance type safety:
📝 Committable suggestion