Skip to content
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

feat: kotlin wrapper for ably-java and ably-android #1064

Merged
merged 3 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.vanniktech.maven.publish.SonatypeHost

plugins {
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.maven.publish) apply false
alias(libs.plugins.lombok) apply false
alias(libs.plugins.test.retry) apply false
Expand Down
4 changes: 3 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ firebase-messaging = "22.0.0"
android-test = "1.0.2"
dexmaker = "1.4"
android-retrostreams = "1.7.4"
maven-publish = "0.29.0"
maven-publish = "0.30.0"
lombok = "8.10"
okhttp = "4.12.0"
test-retry = "1.6.0"
kotlin = "2.1.10"

[libraries]
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
Expand Down Expand Up @@ -48,6 +49,7 @@ tests = ["junit","hamcrest-all", "nanohttpd", "nanohttpd-nanolets", "nanohttpd-w
instrumental-android = ["android-test-runner", "android-test-rules", "dexmaker", "dexmaker-dx", "dexmaker-mockito", "android-retrostreams"]

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
android-library = { id = "com.android.library", version.ref = "agp" }
build-config = { id = "com.github.gmazzo.buildconfig", version.ref = "build-config" }
maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "maven-publish" }
Expand Down
10 changes: 10 additions & 0 deletions pubsub-adapter/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
plugins {
`java-library`
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.maven.publish)
}

dependencies {
compileOnly(project(":java"))
testImplementation(project(":java"))
}
4 changes: 4 additions & 0 deletions pubsub-adapter/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
POM_ARTIFACT_ID=pubsub-adapter
POM_NAME=Internal Ably PubSub adapter
POM_DESCRIPTION=Internal adapter for using Ably PubSub in Kotlin
POM_PACKAGING=jar
12 changes: 12 additions & 0 deletions pubsub-adapter/src/main/kotlin/com/ably/Subscription.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ably

/**
* An unsubscription handle, returned by various functions (mostly subscriptions)
* where unsubscription is required.
*/
fun interface Subscription {
/**
* Handle unsubscription (unsubscribe listeners, clean up)
*/
fun unsubscribe()
}
12 changes: 12 additions & 0 deletions pubsub-adapter/src/main/kotlin/com/ably/http/HttpMethod.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ably.http

enum class HttpMethod(private val method: String) {
Get("GET"),
Post("POST"),
Put("PUT"),
Delete("DELETE"),
Patch("PATCH"),
;

override fun toString() = method
}
65 changes: 65 additions & 0 deletions pubsub-adapter/src/main/kotlin/com/ably/pubsub/Channel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.ably.pubsub

import com.ably.query.OrderBy
import io.ably.lib.types.*

/**
* An interface representing a Channel in the Ably API.
*/
interface Channel {

/**
* The channel name.
*/
val name: String

/**
* A [Presence] object.
*
*
* Spec: RTL9
*/
val presence: Presence

/**
* Obtain recent history for this channel using the REST API.
* The history provided relates to all clients of this application,
* not just this instance.
*
* @param start The start of the query interval as a time in milliseconds since the epoch.
* A message qualifies as a member of the result set if it was received at or after this time. (default: beginning of time)
* @param end The end of the query interval as a time in milliseconds since the epoch.
* A message qualifies as a member of the result set if it was received at or before this time. (default: now)
* @param limit The maximum number of records to return. A limit greater than 1,000 is invalid.
* @param orderBy The direction of this query.
*
* @return Paginated result of Messages for this Channel.
*/
fun history(
start: Long? = null,
end: Long? = null,
limit: Int = 100,
orderBy: OrderBy = OrderBy.NewestFirst,
): PaginatedResult<Message>

/**
* Asynchronously obtain recent history for this channel using the REST API.
*
* @param start The start of the query interval as a time in milliseconds since the epoch.
* A message qualifies as a member of the result set if it was received at or after this time. (default: beginning of time)
* @param end The end of the query interval as a time in milliseconds since the epoch.
* A message qualifies as a member of the result set if it was received at or before this time. (default: now)
* @param limit The maximum number of records to return. A limit greater than 1,000 is invalid.
* @param orderBy The direction of this query.
* @param callback A Callback returning [AsyncPaginatedResult] object containing an array of [Message] objects.
* Note: This callback is invoked on a background thread.
*/
fun historyAsync(
callback: Callback<AsyncPaginatedResult<Message>>,
start: Long? = null,
end: Long? = null,
limit: Int = 100,
orderBy: OrderBy = OrderBy.NewestFirst,
)

}
48 changes: 48 additions & 0 deletions pubsub-adapter/src/main/kotlin/com/ably/pubsub/Channels.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.ably.pubsub

import io.ably.lib.realtime.ChannelState
import io.ably.lib.types.ChannelOptions

/**
* Represents collection of managed Channel instances
*/
interface Channels<ChannelType> : Iterable<ChannelType> {

/**
* Checks if channel with specified name exists
* <p>
* Spec: RSN2, RTS2
* @param name The channel name.
* @return `true` if it contains the specified [name].
*/
fun contains(name: String): Boolean

/**
* Creates a new [Channel] object, or returns the existing channel object.
* <p>
* Spec: RSN3a, RTS3a
* @param name The channel name.
* @return A [Channel] object.
*/
fun get(name: String): ChannelType

/**
* Creates a new [Channel] object, with the specified [ChannelOptions], or returns the existing channel object.
* <p>
* Spec: RSN3c, RTS3c
* @param name The channel name.
* @param options A [ChannelOptions] object.
* @return A [Channel] object.
*/
fun get(name: String, options: ChannelOptions): ChannelType

/**
* Releases a [Channel] object, deleting it, and enabling it to be garbage collected.
* It also removes any listeners associated with the channel.
* To release a channel, the [ChannelState] must be `INITIALIZED`, `DETACHED`, or `FAILED`.
* <p>
* Spec: RSN4, RTS4
* @param name The channel name.
*/
fun release(name: String)
}
174 changes: 174 additions & 0 deletions pubsub-adapter/src/main/kotlin/com/ably/pubsub/Client.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package com.ably.pubsub

import com.ably.query.OrderBy
import com.ably.query.TimeUnit
import com.ably.http.HttpMethod
import io.ably.lib.http.HttpCore
import io.ably.lib.push.Push
import io.ably.lib.rest.Auth
import io.ably.lib.types.*

/**
* A client that offers a base interface to interact with Ably's API.
*
* This class implements {@link AutoCloseable} so you can use it in
* try-with-resources constructs and have the JDK close it for you.
*/
interface Client : AutoCloseable {

/**
* An [Auth] object.
*
* Spec: RSC5
*/
val auth: Auth

/**
* A [Channels] object.
*
* Spec: RTC3, RTS1
*/
val channels: Channels<out Channel>

/**
* Client options
*/
val options: ClientOptions

/**
* An [Push] object.
*
* Spec: RSH7
*/
val push: Push

/**
* Retrieves the time from the Ably service as milliseconds
* since the Unix epoch. Clients that do not have access
* to a sufficiently well maintained time source and wish
* to issue Ably [Auth.TokenRequest] with
* a more accurate timestamp should use the
* [ClientOptions.queryTime] property instead of this method.
* <p>
* Spec: RSC16
* @return The time as milliseconds since the Unix epoch.
*/
fun time(): Long

/**
* Asynchronously retrieves the time from the Ably service as milliseconds
* since the Unix epoch. Clients that do not have access
* to a sufficiently well maintained time source and wish
* to issue Ably [Auth.TokenRequest] with
* a more accurate timestamp should use the
* [ClientOptions.queryTime] property instead of this method.
*
* Spec: RSC16
*
* @param callback Listener with the time as milliseconds since the Unix epoch.
* This callback is invoked on a background thread
*/
fun timeAsync(callback: Callback<Long>)

/**
* Queries the REST /stats API and retrieves your application's usage statistics.
* @param start (RSC6b1) - The time from which stats are retrieved, specified as milliseconds since the Unix epoch.
* @param end (RSC6b1) - The time until stats are retrieved, specified as milliseconds since the Unix epoch.
* @param orderBy (RSC6b2) - The order for which stats are returned in.
* @param limit (RSC6b3) - An upper limit on the number of stats returned. The default is 100, and the maximum is 1000.
* @param unit (RSC6b4) - minute, hour, day or month. Based on the unit selected, the given start or end times are rounded down to the start of the relevant interval depending on the unit granularity of the query.
*
* Spec: RSC6a
*
* @return A [PaginatedResult] object containing an array of [Stats] objects.
* @throws AblyException
*/
fun stats(
start: Long? = null,
end: Long? = null,
limit: Int = 100,
orderBy: OrderBy = OrderBy.NewestFirst,
unit: TimeUnit = TimeUnit.Minute,
): PaginatedResult<Stats>

/**
* Asynchronously queries the REST /stats API and retrieves your application's usage statistics.
*
* @param start (RSC6b1) - The time from which stats are retrieved, specified as milliseconds since the Unix epoch.
* @param end (RSC6b1) - The time until stats are retrieved, specified as milliseconds since the Unix epoch.
* @param orderBy (RSC6b2) - The order for which stats are returned in.
* @param limit (RSC6b3) - An upper limit on the number of stats returned. The default is 100, and the maximum is 1000.
* @param unit (RSC6b4) - minute, hour, day or month. Based on the unit selected, the given start or end times are rounded down to the start of the relevant interval depending on the unit granularity of the query.
*
* Spec: RSC6a
*
* @param callback Listener which returns a [AsyncPaginatedResult] object containing an array of [Stats] objects.
* This callback is invoked on a background thread
*/
fun statsAsync(
callback: Callback<AsyncPaginatedResult<Stats>>,
start: Long? = null,
end: Long? = null,
limit: Int = 100,
orderBy: OrderBy = OrderBy.NewestFirst,
unit: TimeUnit = TimeUnit.Minute,
)

/**
* Makes a REST request to a provided path. This is provided as a convenience
* for developers who wish to use REST API functionality that is either not
* documented or is not yet included in the public API, without having to
* directly handle features such as authentication, paging, fallback hosts,
* MsgPack and JSON support.
*
* Spec: RSC19
*
* @param method The request method to use, such as GET, POST.
* @param path The request path.
* @param params The parameters to include in the URL query of the request.
* The parameters depend on the endpoint being queried.
* See the [REST API reference](https://ably.com/docs/api/rest-api)
* for the available parameters of each endpoint.
* @param body The RequestBody of the request.
* @param headers Additional HTTP headers to include in the request.
* @return An [HttpPaginatedResponse] object returned by the HTTP request, containing an empty or JSON-encodable object.
*/
fun request(
path: String,
method: HttpMethod = HttpMethod.Get,
params: List<Param> = emptyList(),
body: HttpCore.RequestBody? = null,
headers: List<Param> = emptyList(),
): HttpPaginatedResponse

/**
* Makes a async REST request to a provided path. This is provided as a convenience
* for developers who wish to use REST API functionality that is either not
* documented or is not yet included in the public API, without having to
* directly handle features such as authentication, paging, fallback hosts,
* MsgPack and JSON support.
*
* Spec: RSC19
*
* @param method The request method to use, such as GET, POST.
* @param path The request path.
* @param params The parameters to include in the URL query of the request.
* The parameters depend on the endpoint being queried.
* See the [REST API reference](https://ably.com/docs/api/rest-api)
* for the available parameters of each endpoint.
* @param body The RequestBody of the request.
* @param headers Additional HTTP headers to include in the request.
* @param callback called with the asynchronous result,
* returns an [AsyncHttpPaginatedResponse] object returned by the HTTP request,
* containing an empty or JSON-encodable object.
* This callback is invoked on a background thread
*/
fun requestAsync(
path: String,
callback: AsyncHttpPaginatedResponse.Callback,
method: HttpMethod = HttpMethod.Get,
params: List<Param> = emptyList(),
body: HttpCore.RequestBody? = null,
headers: List<Param> = emptyList(),
)
}
Loading
Loading