Skip to content

Commit

Permalink
feat: Rest and Realtime clients adapters
Browse files Browse the repository at this point in the history
Adapters for the Kotlin API for `ably-java` and `ably-android`
  • Loading branch information
ttypic committed Feb 12, 2025
1 parent 4ca1ae8 commit 227a060
Show file tree
Hide file tree
Showing 9 changed files with 413 additions and 0 deletions.
28 changes: 28 additions & 0 deletions pubsub-adapter/src/main/kotlin/io/ably/lib/Utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.ably.lib

import com.ably.query.Direction
import com.ably.query.TimeUnit
import io.ably.lib.types.Param

fun buildStatsParams(
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
unit: TimeUnit,
) = buildList {
addAll(buildHistoryParams(start, end, limit, direction))
add(Param("unit", unit.toString()))
}

fun buildHistoryParams(
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
) = buildList {
start?.let { add(Param("start", it)) }
end?.let { add(Param("end", it)) }
add(Param("limit", limit))
add(Param("direction", direction.toString()))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.ably.lib.realtime

import com.ably.Subscription
import com.ably.pubsub.RealtimeChannel
import com.ably.pubsub.RealtimePresence
import com.ably.query.Direction
import io.ably.lib.buildHistoryParams
import io.ably.lib.types.*

internal class RealtimeChannelAdapter(private val legacyChannel: Channel) : RealtimeChannel {
override val name: String
get() = legacyChannel.name
override val presence: RealtimePresence
get() = RealtimePresenceAdapter(legacyChannel.presence)
override val state: ChannelState
get() = legacyChannel.state
override val reason: ErrorInfo
get() = legacyChannel.reason
override val properties: ChannelProperties
get() = legacyChannel.properties

override fun attach(listener: CompletionListener?) = legacyChannel.attach(listener)

override fun detach(listener: CompletionListener?) = legacyChannel.detach(listener)

override fun subscribe(listener: ChannelBase.MessageListener): Subscription {
legacyChannel.subscribe(listener)
return Subscription {
legacyChannel.unsubscribe(listener)
}
}

override fun subscribe(eventName: String, listener: ChannelBase.MessageListener): Subscription {
legacyChannel.subscribe(eventName, listener)
return Subscription {
legacyChannel.unsubscribe(eventName, listener)
}
}

override fun subscribe(eventNames: List<String>, listener: ChannelBase.MessageListener): Subscription {
legacyChannel.subscribe(eventNames.toTypedArray(), listener)
return Subscription {
legacyChannel.unsubscribe(eventNames.toTypedArray(), listener)
}
}

override fun publish(name: String, data: Any, listener: CompletionListener?) =
legacyChannel.publish(name, data, listener)

override fun publish(message: Message, listener: CompletionListener?) = legacyChannel.publish(message, listener)

override fun publish(messages: List<Message>, listener: CompletionListener?) =
legacyChannel.publish(messages.toTypedArray(), listener)

override fun history(start: Long?, end: Long?, limit: Int, direction: Direction): PaginatedResult<Message> =
legacyChannel.history(buildHistoryParams(start, end, limit, direction).toTypedArray())

override fun historyAsync(
callback: Callback<AsyncPaginatedResult<Message>>,
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
) =
legacyChannel.historyAsync(buildHistoryParams(start, end, limit, direction).toTypedArray(), callback)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.ably.lib.realtime

import com.ably.pubsub.Channels
import com.ably.pubsub.RealtimeChannel
import io.ably.lib.types.ChannelOptions

internal class RealtimeChannelsAdapter(private val legacyChannels: AblyRealtime.Channels) : Channels<RealtimeChannel> {
override fun contains(name: String): Boolean = legacyChannels.containsKey(name)

override fun get(name: String): RealtimeChannel = RealtimeChannelAdapter(legacyChannels.get(name))

override fun get(name: String, options: ChannelOptions): RealtimeChannel =
RealtimeChannelAdapter(legacyChannels.get(name, options))

override fun release(name: String) = legacyChannels.release(name)

override fun iterator(): Iterator<RealtimeChannel> = iterator {
legacyChannels.entrySet().forEach { yield(RealtimeChannelAdapter(it.value)) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package io.ably.lib.realtime

import com.ably.http.HttpMethod
import com.ably.pubsub.Channels
import com.ably.pubsub.RealtimeChannel
import com.ably.pubsub.RealtimeClient
import com.ably.query.Direction
import com.ably.query.TimeUnit
import io.ably.lib.buildStatsParams
import io.ably.lib.http.HttpCore
import io.ably.lib.push.Push
import io.ably.lib.rest.Auth
import io.ably.lib.types.*

/**
* Wrapper for Realtime client
*/
fun RealtimeClient(legacyClient: AblyRealtime): RealtimeClient = RealtimeClientAdapter(legacyClient)

internal class RealtimeClientAdapter(private val legacyClient: AblyRealtime) : RealtimeClient {
override val channels: Channels<out RealtimeChannel>
get() = RealtimeChannelsAdapter(legacyClient.channels)
override val connection: Connection
get() = legacyClient.connection
override val auth: Auth
get() = legacyClient.auth
override val options: ClientOptions
get() = legacyClient.options
override val push: Push
get() = legacyClient.push

override fun time(): Long = legacyClient.time()

override fun timeAsync(callback: Callback<Long>) = legacyClient.timeAsync(callback)

override fun stats(
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
unit: TimeUnit
): PaginatedResult<Stats> = legacyClient.stats(buildStatsParams(start, end, limit, direction, unit).toTypedArray())

override fun statsAsync(
callback: Callback<AsyncPaginatedResult<Stats>>,
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
unit: TimeUnit
) = legacyClient.statsAsync(buildStatsParams(start, end, limit, direction, unit).toTypedArray(), callback)

override fun request(
path: String,
method: HttpMethod,
params: List<Param>,
body: HttpCore.RequestBody?,
headers: List<Param>,
) = legacyClient.request(method.toString(), path, params.toTypedArray(), body, headers.toTypedArray())!!

override fun requestAsync(
path: String,
callback: AsyncHttpPaginatedResponse.Callback,
method: HttpMethod,
params: List<Param>,
body: HttpCore.RequestBody?,
headers: List<Param>,
) = legacyClient.requestAsync(method.toString(), path, params.toTypedArray(), body, headers.toTypedArray(), callback)

override fun close() = legacyClient.close()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.ably.lib.realtime

import com.ably.Subscription
import com.ably.pubsub.RealtimePresence
import com.ably.query.Direction
import io.ably.lib.buildHistoryParams
import io.ably.lib.types.*
import java.util.*

internal class RealtimePresenceAdapter(private val legacyPresence: Presence) : RealtimePresence {
override fun get(clientId: String?, connectionId: String?, waitForSync: Boolean): List<PresenceMessage> {
val params = buildList {
clientId?.let { add(Param(Presence.GET_CLIENTID, it)) }
connectionId?.let { add(Param(Presence.GET_CONNECTIONID, it)) }
add(Param(Presence.GET_WAITFORSYNC, waitForSync))
}
return legacyPresence.get(*params.toTypedArray()).toList()
}

override fun subscribe(listener: Presence.PresenceListener): Subscription {
legacyPresence.subscribe(listener)
return Subscription {
legacyPresence.unsubscribe(listener)
}
}

override fun subscribe(
action: PresenceMessage.Action,
listener: Presence.PresenceListener,
): Subscription {
legacyPresence.subscribe(action, listener)
return Subscription {
legacyPresence.unsubscribe(action, listener)
}
}

override fun subscribe(
actions: EnumSet<PresenceMessage.Action>,
listener: Presence.PresenceListener,
): Subscription {
legacyPresence.subscribe(actions, listener)
return Subscription {
legacyPresence.unsubscribe(actions, listener)
}
}

override fun enter(data: Any?, listener: CompletionListener?) = legacyPresence.enter(data, listener)

override fun update(data: Any?, listener: CompletionListener?) = legacyPresence.update(data, listener)

override fun leave(data: Any?, listener: CompletionListener?) = legacyPresence.leave(data, listener)

override fun enterClient(clientId: String, data: Any?, listener: CompletionListener?) =
legacyPresence.enterClient(clientId, data, listener)

override fun updateClient(clientId: String, data: Any?, listener: CompletionListener?) =
legacyPresence.updateClient(clientId, data, listener)

override fun leaveClient(clientId: String?, data: Any?, listener: CompletionListener?) =
legacyPresence.leaveClient(clientId, data, listener)

override fun updatePresence(msg: PresenceMessage, listener: CompletionListener?) =
legacyPresence.updatePresence(msg, listener)

override fun history(start: Long?, end: Long?, limit: Int, direction: Direction): PaginatedResult<PresenceMessage> =
legacyPresence.history(buildHistoryParams(start, end, limit, direction).toTypedArray())

override fun historyAsync(
callback: Callback<AsyncPaginatedResult<PresenceMessage>>,
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
) =
legacyPresence.historyAsync(buildHistoryParams(start, end, limit, direction).toTypedArray(), callback)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.ably.lib.rest

import com.ably.pubsub.RestChannel
import com.ably.pubsub.RestPresence
import com.ably.query.Direction
import io.ably.lib.buildHistoryParams
import io.ably.lib.realtime.CompletionListener
import io.ably.lib.types.*

internal class RestChannelAdapter(private val legacyChannel: Channel) : RestChannel {
override val name: String
get() = legacyChannel.name

override val presence: RestPresence
get() = RestPresenceAdapter(legacyChannel.presence)

override fun publish(name: String, data: Any) = legacyChannel.publish(name, data)

override fun publish(messages: List<Message>) = legacyChannel.publish(messages.toTypedArray())

override fun publishAsync(name: String, data: Any, listener: CompletionListener) =
legacyChannel.publishAsync(name, data, listener)

override fun publishAsync(messages: List<Message>, listener: CompletionListener) =
legacyChannel.publishAsync(messages.toTypedArray(), listener)

override fun history(start: Long?, end: Long?, limit: Int, direction: Direction): PaginatedResult<Message> =
legacyChannel.history(buildHistoryParams(start, end, limit, direction).toTypedArray())

override fun historyAsync(
callback: Callback<AsyncPaginatedResult<Message>>,
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
) =
legacyChannel.historyAsync(buildHistoryParams(start, end, limit, direction).toTypedArray(), callback)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.ably.lib.rest

import com.ably.pubsub.Channels
import com.ably.pubsub.RestChannel
import io.ably.lib.types.ChannelOptions

internal class RestChannelsAdapter(private val legacyChannels: AblyBase.Channels) : Channels<RestChannel> {
override fun contains(name: String): Boolean = legacyChannels.containsKey(name)

override fun get(name: String): RestChannel = RestChannelAdapter(legacyChannels.get(name))

override fun get(name: String, options: ChannelOptions): RestChannel =
RestChannelAdapter(legacyChannels.get(name, options))

override fun release(name: String) = legacyChannels.release(name)

override fun iterator(): Iterator<RestChannel> = iterator {
legacyChannels.entrySet().forEach { yield(RestChannelAdapter(it.value)) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.ably.lib.rest

import com.ably.http.HttpMethod
import com.ably.pubsub.Channels
import com.ably.pubsub.RestChannel
import com.ably.pubsub.RestClient
import com.ably.query.Direction
import com.ably.query.TimeUnit
import io.ably.lib.buildStatsParams
import io.ably.lib.http.HttpCore
import io.ably.lib.push.Push
import io.ably.lib.types.*

/**
* Wrapper for Rest client
*/
fun RestClient(legacyClient: AblyRest): RestClient = RestClientAdapter(legacyClient)

internal class RestClientAdapter(private val legacyClient: AblyRest) : RestClient {
override val channels: Channels<out RestChannel>
get() = RestChannelsAdapter(legacyClient.channels)
override val auth: Auth
get() = legacyClient.auth
override val options: ClientOptions
get() = legacyClient.options
override val push: Push
get() = legacyClient.push

override fun time(): Long = legacyClient.time()

override fun timeAsync(callback: Callback<Long>) = legacyClient.timeAsync(callback)

override fun stats(
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
unit: TimeUnit
): PaginatedResult<Stats> = legacyClient.stats(buildStatsParams(start, end, limit, direction, unit).toTypedArray())

override fun statsAsync(
callback: Callback<AsyncPaginatedResult<Stats>>,
start: Long?,
end: Long?,
limit: Int,
direction: Direction,
unit: TimeUnit
) = legacyClient.statsAsync(buildStatsParams(start, end, limit, direction, unit).toTypedArray(), callback)

override fun request(
path: String,
method: HttpMethod,
params: List<Param>,
body: HttpCore.RequestBody?,
headers: List<Param>,
) = legacyClient.request(method.toString(), path, params.toTypedArray(), body, headers.toTypedArray())!!

override fun requestAsync(
path: String,
callback: AsyncHttpPaginatedResponse.Callback,
method: HttpMethod,
params: List<Param>,
body: HttpCore.RequestBody?,
headers: List<Param>,
) = legacyClient.requestAsync(method.toString(), path, params.toTypedArray(), body, headers.toTypedArray(), callback)

override fun close() = legacyClient.close()
}
Loading

0 comments on commit 227a060

Please sign in to comment.