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 response models #300

Merged
merged 9 commits into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 15 additions & 3 deletions src/SDK/Language/Kotlin.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public function getTypeName($type)
{
switch ($type) {
case self::TYPE_INTEGER:
return 'Int';
return 'Long';
case self::TYPE_NUMBER:
return 'Double';
case self::TYPE_STRING:
Expand Down Expand Up @@ -354,7 +354,13 @@ public function getFiles()
],
[
'scope' => 'default',
'destination' => '/src/main/kotlin/{{ sdk.namespace | caseSlash }}/services/BaseService.kt',
'destination' => '/src/main/kotlin/{{ sdk.namespace | caseSlash }}/json/PreciseNumberAdapter.kt',
'template' => '/kotlin/src/main/kotlin/io/appwrite/json/PreciseNumberAdapter.kt.twig',
'minify' => false,
],
[
'scope' => 'default',
'destination' => '/src/main/kotlin/{{ sdk.namespace | caseSlash }}/services/Service.kt',
'template' => '/kotlin/src/main/kotlin/io/appwrite/services/Service.kt.twig',
'minify' => false,
],
Expand All @@ -363,7 +369,13 @@ public function getFiles()
'destination' => '/src/main/kotlin/{{ sdk.namespace | caseSlash }}/services/{{service.name | caseUcfirst}}.kt',
'template' => '/kotlin/src/main/kotlin/io/appwrite/services/ServiceTemplate.kt.twig',
'minify' => false,
]
],
[
'scope' => 'definition',
'destination' => '/src/main/kotlin/{{ sdk.namespace | caseSlash }}/models/{{ definition.name | caseUcfirst }}.kt',
'template' => '/kotlin/src/main/kotlin/io/appwrite/models/Model.kt.twig',
'minify' => false,
],
];
}
}
Expand Down
6 changes: 3 additions & 3 deletions templates/kotlin/.github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up JDK 1.8
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 1.8
java-version: 11
# Base64 decodes and pipes the GPG key content into the secret file
- name: Prepare environment
env:
Expand All @@ -41,4 +41,4 @@ jobs:
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.SIGNING_SECRET_KEY_RING_FILE }}
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
7 changes: 3 additions & 4 deletions templates/kotlin/build.gradle.twig
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.4.32'
id 'org.jetbrains.kotlin.jvm' version '1.5.31'
id 'java-library'
}


ext {
PUBLISH_GROUP_ID = '{{ sdk.namespace | caseDot }}'
PUBLISH_ARTIFACT_ID = '{{ sdk.gitRepoName | caseDash }}'
Expand All @@ -27,12 +26,12 @@ repositories {
}

dependencies {
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3")
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
api(platform("com.squareup.okhttp3:okhttp-bom:4.9.0"))
api("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:okhttp-urlconnection")
implementation("com.squareup.okhttp3:logging-interceptor")
implementation("com.google.code.gson:gson:2.8.5")
implementation("com.google.code.gson:gson:2.8.7")

testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
}
Expand Down
2 changes: 1 addition & 1 deletion templates/kotlin/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
1 change: 0 additions & 1 deletion templates/kotlin/settings.gradle.twig
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@

rootProject.name = '{{ sdk.gitRepoName | caseDash }}'

126 changes: 87 additions & 39 deletions templates/kotlin/src/main/kotlin/io/appwrite/Client.kt.twig
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package {{ sdk.namespace | caseDot }}

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import {{ sdk.namespace | caseDot }}.exceptions.{{ spec.title | caseUcfirst }}Exception
import {{ sdk.namespace | caseDot }}.extensions.fromJson
import {{ sdk.namespace | caseDot }}.json.PreciseNumberAdapter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
Expand All @@ -14,6 +16,7 @@ import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.logging.HttpLoggingInterceptor
import java.io.BufferedInputStream
import java.io.BufferedReader
import java.io.File
import java.io.IOException
Expand All @@ -37,12 +40,18 @@ class Client @JvmOverloads constructor(

private val job = Job()

private lateinit var http: OkHttpClient
private val gson = GsonBuilder().registerTypeAdapter(
object : TypeToken<Map<String, Any>>(){}.type,
PreciseNumberAdapter()
).create()

lateinit var http: OkHttpClient

private val headers: MutableMap<String, String>

val config: MutableMap<String, String>


init {
headers = mutableMapOf(
"content-type" to "application/json",
Expand All @@ -54,7 +63,7 @@ class Client @JvmOverloads constructor(

)
config = mutableMapOf()

setSelfSigned(selfSigned)
}

Expand All @@ -79,10 +88,10 @@ class Client @JvmOverloads constructor(
{% endfor %}
/**
* Set self Signed
*
*
* @param status
*
* @return this
* @return this
*/
fun setSelfSigned(status: Boolean): Client {
selfSigned = status
Expand All @@ -98,9 +107,12 @@ class Client @JvmOverloads constructor(
try {
// Create a trust manager that does not validate certificate chains
val trustAllCerts = arrayOf<TrustManager>(
@Suppress("CustomX509TrustManager")
object : X509TrustManager {
@Suppress("TrustAllX509TrustManager")
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
}
@Suppress("TrustAllX509TrustManager")
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
}
override fun getAcceptedIssuers(): Array<X509Certificate> {
Expand Down Expand Up @@ -139,11 +151,11 @@ class Client @JvmOverloads constructor(

/**
* Add Header
*
*
* @param key
* @param value
*
* @return this
* @return this
*/
fun addHeader(key: String, value: String): Client {
headers[key] = value
Expand All @@ -152,22 +164,23 @@ class Client @JvmOverloads constructor(

/**
* Send the HTTP request
*
*
* @param method
* @param path
* @param headers
* @param params
*
* @return [Response]
* @return [Response]
*/
@Throws({{ spec.title | caseUcfirst }}Exception::class)
suspend fun call(
method: String,
path: String,
headers: Map<String, String> = mapOf(),
params: Map<String, Any?> = mapOf()
): Response {

suspend fun <T> call(
method: String,
path: String,
headers: Map<String, String> = mapOf(),
params: Map<String, Any?> = mapOf(),
responseType: Class<T>,
convert: ((Map<String, Any,>) -> T)? = null
): T {
val filteredParams = params.filterValues { it != null }

val requestHeaders = this.headers.toHeaders().newBuilder()
Expand Down Expand Up @@ -202,7 +215,7 @@ class Client @JvmOverloads constructor(
.get()
.build()

return awaitResponse(request)
return awaitResponse(request, responseType, convert)
}

val body = if (MultipartBody.FORM.toString() == headers["content-type"]) {
Expand Down Expand Up @@ -230,7 +243,7 @@ class Client @JvmOverloads constructor(
}
builder.build()
} else {
Gson().toJson(filteredParams)
gson.toJson(filteredParams)
.toRequestBody("application/json".toMediaType())
}

Expand All @@ -240,21 +253,24 @@ class Client @JvmOverloads constructor(
.method(method, body)
.build()

return awaitResponse(request)
return awaitResponse(request, responseType, convert)
}

/**
* Await Response
*
* @param method
* @param path
* @param headers
* @param params
*
* @return [Response]
* @param request
* @param responseType
* @param convert
*
* @return [T]
*/
@Throws({{ spec.title | caseUcfirst }}Exception::class)
private suspend fun awaitResponse(request: Request) = suspendCancellableCoroutine<Response> {
private suspend fun <T> awaitResponse(
request: Request,
responseType: Class<T>,
convert: ((Map<String, Any,>) -> T)? = null
) = suspendCancellableCoroutine<T> {
http.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
if (it.isCancelled) {
Expand All @@ -263,23 +279,55 @@ class Client @JvmOverloads constructor(
it.cancel(e)
}

@Suppress("UNCHECKED_CAST")
override fun onResponse(call: Call, response: Response) {
if (response.code >= 400) {
val bodyString = response.body
?.charStream()
?.buffered()
?.use(BufferedReader::readText) ?: ""

val contentType: String = response.headers["content-type"] ?: ""
val error = if (contentType.contains("application/json", ignoreCase = true)) {
bodyString.fromJson()
if (!response.isSuccessful) {
val body = response.body!!
.charStream()
.buffered()
.use(BufferedReader::readText)
val error = if (response.headers["content-type"]?.contains("application/json") == true) {
body.fromJson()
} else {
{{ spec.title | caseUcfirst }}Exception(bodyString, response.code)
{{ spec.title | caseUcfirst }}Exception(body, response.code)
}
it.cancel(error)
return
}
when {
responseType == Boolean::class.java -> {
it.resume(true as T)
return
}
responseType == ByteArray::class.java -> {
it.resume(response.body!!
.byteStream()
.buffered()
.use(BufferedInputStream::readBytes) as T
)
return
}
response.body == null -> {
it.resume(true as T)
return
}
}
val body = response.body!!
.charStream()
.buffered()
.use(BufferedReader::readText)
if (body.isEmpty()) {
it.resume(true as T)
return
}
it.resume(response)
val map = gson.fromJson<Map<String, Any>>(
body,
object : TypeToken<Map<String, Any>>(){}.type
)
it.resume(
convert?.invoke(map) ?: map as T
)
}
})
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ inline fun <reified T> Any.tryJsonCast(): T? = try {
} catch (ex: Exception) {
ex.printStackTrace()
null
}
}
Loading