Skip to content

Commit d6792c1

Browse files
Merge pull request #243 from appwrite/feat-android-realtime
Feat android/kotlin realtime
2 parents 726b69e + 6f37805 commit d6792c1

File tree

13 files changed

+345
-44
lines changed

13 files changed

+345
-44
lines changed

src/SDK/Language/Android.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,14 @@ public function getFiles()
136136
],
137137
[
138138
'scope' => 'default',
139-
'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/models/Error.kt',
140-
'template' => '/android/library/src/main/java/io/appwrite/models/Error.kt.twig',
139+
'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/extensions/CollectionExtensions.kt',
140+
'template' => '/android/library/src/main/java/io/appwrite/extensions/CollectionExtensions.kt.twig',
141+
'minify' => false,
142+
],
143+
[
144+
'scope' => 'default',
145+
'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/models/RealtimeModels.kt',
146+
'template' => '/android/library/src/main/java/io/appwrite/models/RealtimeModels.kt.twig',
141147
'minify' => false,
142148
],
143149
[
@@ -160,10 +166,16 @@ public function getFiles()
160166
],
161167
[
162168
'scope' => 'default',
163-
'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/services/BaseService.kt',
169+
'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/services/Service.kt',
164170
'template' => '/android/library/src/main/java/io/appwrite/services/Service.kt.twig',
165171
'minify' => false,
166172
],
173+
[
174+
'scope' => 'default',
175+
'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/services/Realtime.kt',
176+
'template' => '/android/library/src/main/java/io/appwrite/services/Realtime.kt.twig',
177+
'minify' => false,
178+
],
167179
[
168180
'scope' => 'service',
169181
'destination' => '/library/src/main/java/{{ sdk.namespace | caseSlash }}/services/{{service.name | caseUcfirst}}.kt',

templates/android/.github/workflows/publish.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ jobs:
5050
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
5151
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
5252
SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.SIGNING_SECRET_KEY_RING_FILE }}
53-
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
53+
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
54+
SDK_VERSION: ${{ github.event.release.tag_name }}

templates/android/library/build.gradle.twig

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77
ext {
88
PUBLISH_GROUP_ID = '{{ sdk.namespace | caseDot }}'
99
PUBLISH_ARTIFACT_ID = '{{ sdk.gitRepoName | caseDash }}'
10-
PUBLISH_VERSION = '{{ sdk.version }}'
10+
PUBLISH_VERSION = System.getenv('SDK_VERSION')
1111
POM_URL = 'https://github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName }}'
1212
POM_SCM_URL = 'https://github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName }}'
1313
POM_ISSUE_URL = 'https://github.com/{{ sdk.gitUserName }}/{{ sdk.gitRepoName }}/issues'
@@ -53,8 +53,8 @@ android {
5353

5454
dependencies {
5555
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${KotlinCompilerVersion.VERSION}")
56-
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3")
57-
api("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3")
56+
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1")
57+
api("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0")
5858

5959
api(platform("com.squareup.okhttp3:okhttp-bom:4.9.0"))
6060
api("com.squareup.okhttp3:okhttp")
@@ -65,15 +65,16 @@ dependencies {
6565
implementation("net.gotev:cookie-store:1.3.5")
6666
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.1")
6767
implementation("androidx.lifecycle:lifecycle-common-java8:2.3.1")
68-
implementation("androidx.appcompat:appcompat:1.2.0")
69-
implementation("androidx.fragment:fragment-ktx:1.3.2")
70-
implementation("androidx.activity:activity-ktx:1.2.2")
68+
implementation("androidx.appcompat:appcompat:1.3.1")
69+
implementation("androidx.fragment:fragment-ktx:1.3.6")
70+
implementation("androidx.activity:activity-ktx:1.3.1")
7171
implementation("androidx.browser:browser:1.3.0")
7272

7373
testImplementation 'junit:junit:4.+'
74-
testImplementation "androidx.test.ext:junit-ktx:1.1.2"
75-
testImplementation "androidx.test:core-ktx:1.3.0"
74+
testImplementation "androidx.test.ext:junit-ktx:1.1.3"
75+
testImplementation "androidx.test:core-ktx:1.4.0"
7676
testImplementation "org.robolectric:robolectric:4.5.1"
77+
testApi("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.1")
7778
}
7879

7980
apply from: "${rootProject.projectDir}/scripts/publish-module.gradle"

templates/android/library/src/main/java/io/appwrite/Client.kt.twig

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import android.content.pm.PackageManager
55
import com.google.gson.Gson
66
import io.appwrite.appwrite.BuildConfig
77
import {{ sdk.namespace | caseDot }}.exceptions.{{ spec.title | caseUcfirst }}Exception
8-
import {{ sdk.namespace | caseDot }}.extensions.JsonExtensions.fromJson
9-
import {{ sdk.namespace | caseDot }}.models.Error
8+
import {{ sdk.namespace | caseDot }}.extensions.fromJson
109
import kotlinx.coroutines.CoroutineScope
1110
import kotlinx.coroutines.Dispatchers
1211
import kotlinx.coroutines.Job
@@ -36,6 +35,7 @@ import kotlin.coroutines.resume
3635
class Client @JvmOverloads constructor(
3736
context: Context,
3837
var endPoint: String = "https://appwrite.io/v1",
38+
var endPointRealtime: String? = null,
3939
private var selfSigned: Boolean = false
4040
) : CoroutineScope {
4141

@@ -151,14 +151,31 @@ class Client @JvmOverloads constructor(
151151
}
152152

153153
/**
154-
* Set endpoint
154+
* Set endpoint and realtime endpoint.
155155
*
156156
* @param endpoint
157157
*
158158
* @return this
159159
*/
160160
fun setEndpoint(endPoint: String): Client {
161161
this.endPoint = endPoint
162+
163+
if (this.endPointRealtime == null && endPoint.startsWith("http")) {
164+
this.endPointRealtime = endPoint.replaceFirst("http", "ws")
165+
}
166+
167+
return this
168+
}
169+
170+
/**
171+
* Set realtime endpoint
172+
*
173+
* @param endpoint
174+
*
175+
* @return this
176+
*/
177+
fun setEndpointRealtime(endPoint: String): Client {
178+
this.endPointRealtime = endPoint
162179
return this
163180
}
164181

@@ -297,9 +314,9 @@ class Client @JvmOverloads constructor(
297314

298315
val contentType: String = response.headers["content-type"] ?: ""
299316
val error = if (contentType.contains("application/json", ignoreCase = true)) {
300-
bodyString.fromJson(Error::class.java)
317+
bodyString.fromJson<{{ spec.title | caseUcfirst }}Exception>()
301318
} else {
302-
Error(bodyString, response.code)
319+
{{ spec.title | caseUcfirst }}Exception(bodyString, response.code)
303320
}
304321

305322
it.cancel(AppwriteException(
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package {{ sdk.namespace | caseDot }}.extensions
2+
3+
import kotlinx.coroutines.Dispatchers.IO
4+
import kotlinx.coroutines.async
5+
import kotlinx.coroutines.awaitAll
6+
import kotlinx.coroutines.withContext
7+
8+
suspend fun <T> Collection<T>.forEachAsync(
9+
callback: suspend (T) -> Unit
10+
) = withContext(IO) {
11+
map { async { callback.invoke(it) } }.awaitAll()
12+
}

templates/android/library/src/main/java/io/appwrite/extensions/JsonExtensions.kt.twig

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,33 @@ package {{ sdk.namespace | caseDot }}.extensions
22

33
import com.google.gson.Gson
44

5-
object JsonExtensions {
5+
val gson = Gson()
66

7-
fun Any.toJson(): String =
8-
Gson().toJson(this)
7+
fun Any.toJson(): String =
8+
gson.toJson(this)
99

10-
fun <T> String.fromJson(clazz: Class<T>): T =
11-
Gson().fromJson(this, clazz)
12-
}
10+
fun <T> String.fromJson(clazz: Class<T>): T =
11+
gson.fromJson(this, clazz)
12+
13+
inline fun <reified T> String.fromJson(): T =
14+
gson.fromJson(this, T::class.java)
15+
16+
fun <T> Any.jsonCast(to: Class<T>): T =
17+
toJson().fromJson(to)
18+
19+
inline fun <reified T> Any.jsonCast(): T =
20+
toJson().fromJson(T::class.java)
21+
22+
fun <T> Any.tryJsonCast(to: Class<T>): T? = try {
23+
toJson().fromJson(to)
24+
} catch (ex: Exception) {
25+
ex.printStackTrace()
26+
null
27+
}
28+
29+
inline fun <reified T> Any.tryJsonCast(): T? = try {
30+
toJson().fromJson(T::class.java)
31+
} catch (ex: Exception) {
32+
ex.printStackTrace()
33+
null
34+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package {{ sdk.namespace | caseDot }}.models
2+
3+
import java.io.Closeable
4+
5+
data class RealtimeSubscription(
6+
private val close: () -> Unit
7+
) : Closeable {
8+
override fun close() = close.invoke()
9+
}
10+
11+
data class RealtimeCallback(
12+
val payloadClass: Class<*>,
13+
val callback: (RealtimeResponseEvent<*>) -> Unit
14+
)
15+
16+
open class RealtimeResponse(
17+
val type: String,
18+
val data: Any
19+
)
20+
21+
data class RealtimeResponseEvent<T>(
22+
val event: String,
23+
val channels: Collection<String>,
24+
val timestamp: Long,
25+
var payload: T
26+
)
27+
28+
enum class RealtimeCode(val value: Int) {
29+
POLICY_VIOLATION(1008),
30+
UNKNOWN_ERROR(-1)
31+
}

0 commit comments

Comments
 (0)