Skip to content

Commit

Permalink
Libs(Kotlin): reapply local patches to 7.9.0 templates
Browse files Browse the repository at this point in the history
Removes the enum_class mustache and custom serializer impl in the hopes
that the 7.9.0 generator handles these correctly without our patches.

Testing should confirm this. If they are still needed, we'll bring that
stuff back with the tests.

The ApiClient template had a block for running requests as a suspendable
coroutine which _should be present_ since we configure the generator
with `useCoroutines=true`, however I need to learn more kotlin before
I'm confident about how to fit the retry loop around that.

For now, I've left the blocking-style request we've always had in place
(i.e. the block you'd get when `useCoroutines=false`).

Parts of `build.gradle` have been updated to track the generator. The
kotlin version, for example, was needed to get the build working.

N.b. if the build starts hanging for you, clean out the `build` and
`generated` directories since there will be stale artifacts in each that
can interfere.
  • Loading branch information
svix-onelson committed Oct 15, 2024
1 parent 9965f91 commit 569acbc
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 150 deletions.
6 changes: 4 additions & 2 deletions kotlin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ group GROUP
version VERSION_NAME

wrapper {
gradleVersion = '6.8.3'
gradleVersion = '8.7'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}

buildscript {
ext.kotlin_version = '1.5.10'
ext.kotlin_version = '1.9.23'
ext.spotless_version = "6.25.0"

repositories {
maven { url "https://repo1.maven.org/maven2" }
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.diffplug.spotless:spotless-plugin-gradle:$spotless_version"
classpath "io.github.gradle-nexus:publish-plugin:1.1.0"
}
}
Expand Down
2 changes: 1 addition & 1 deletion kotlin/lib/generated/openapi/.openapi-generator-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

src/main/kotlin/com/svix/kotlin/internal/infrastructure/Serializer.kt
# src/main/kotlin/com/svix/kotlin/internal/infrastructure/Serializer.kt

This file was deleted.

67 changes: 0 additions & 67 deletions kotlin/templates/enum_class.mustache

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import com.fasterxml.jackson.core.type.TypeReference
{{#moshi}}
import com.squareup.moshi.adapter
{{/moshi}}
import kotlinx.coroutines.delay
import kotlin.random.Random

{{#nonPublicApi}}internal {{/nonPublicApi}}val EMPTY_REQUEST: RequestBody = ByteArray(0).toRequestBody()

Expand All @@ -69,13 +71,13 @@ import com.squareup.moshi.adapter
protected const val FormDataMediaType = "multipart/form-data"
protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded"
protected const val XmlMediaType = "application/xml"
protected const val UserAgent = "User-Agent"
protected const val OctetMediaType = "application/octet-stream"
val apiKey: MutableMap<String, String> = mutableMapOf()
val apiKeyPrefix: MutableMap<String, String> = mutableMapOf()
var username: String? = null
var password: String? = null
var accessToken: String? = null
const val baseUrlKey = "{{packageName}}.baseUrl"
@JvmStatic
Expand All @@ -87,6 +89,11 @@ import com.squareup.moshi.adapter
val builder: OkHttpClient.Builder = OkHttpClient.Builder()
}

var accessToken: String? = null
var userAgent: String? = null
var initialRetryDelayMillis = 50L
var numRetries: Int = 3

/**
* Guess Content-Type header from the given file (defaults to "application/octet-stream").
*
Expand Down Expand Up @@ -137,6 +144,9 @@ import com.squareup.moshi.adapter
}
mediaType == null || mediaType.startsWith("application/") && mediaType.endsWith("json") ->
if (content == null) {
// FIXME(onelson): double check that this is where we land on DELETE requests
// We initially had to patch the client for responses without a body.
// Ref: https://github.com/svix/svix-webhooks/pull/1124
EMPTY_REQUEST
} else {
{{#moshi}}
Expand Down Expand Up @@ -318,6 +328,13 @@ import com.squareup.moshi.adapter
updateAuthParams(requestConfig)
{{/hasAuthMethods}}

// add user agent
if (requestConfig.headers[UserAgent].isNullOrEmpty()) {
userAgent?.let { userAgent ->
requestConfig.headers[UserAgent] = userAgent
}
}

val url = httpUrl.newBuilder()
.addEncodedPathSegments(requestConfig.path.trimStart('/'))
.apply {
Expand All @@ -332,6 +349,9 @@ import com.squareup.moshi.adapter
if (requestConfig.body != null && requestConfig.headers[ContentType].isNullOrEmpty()) {
requestConfig.headers[ContentType] = JsonMediaType
}
if (requestConfig.headers["svix-req-id"].isNullOrEmpty()) {
requestConfig.headers["svix-req-id"] = Math.abs(Random.nextBits(32)).toString()
}
if (requestConfig.headers[Accept].isNullOrEmpty()) {
requestConfig.headers[Accept] = JsonMediaType
}
Expand Down Expand Up @@ -360,23 +380,26 @@ import com.squareup.moshi.adapter
headers.forEach { header -> addHeader(header.key, header.value) }
}.build()

{{#useCoroutines}}
val response: Response = suspendCancellableCoroutine { continuation ->
val call = client.newCall(request)
continuation.invokeOnCancellation { call.cancel() }
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
continuation.resumeWithException(e)
}
override fun onResponse(call: Call, response: Response) {
continuation.resume(response)
}
})

// FIXME(onelson): the upstream generator template has the below block for the useCoroutines=false case.
// More reading up on kotlin required before it's clear how to do a retry loop over a suspendable.
// For now, we'll do the non-coroutine thing.
// Ref: https://github.com/OpenAPITools/openapi-generator/blob/4145000dfebe7a9edea4555c8515383da7602458/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache#L363-L376
var response = client.newCall(request).execute()

var sleepTime = initialRetryDelayMillis
var retryCount = 0
for (i in 0 until numRetries-1) {
if (response.isSuccessful || response.code < 500) {
break
}
response.close()
retryCount = retryCount.inc()
delay(sleepTime)
sleepTime = sleepTime * 2
var newRequest = request.newBuilder().header("svix-retry-count", retryCount.toString()).build()
response = client.newCall(newRequest).execute()
}
{{/useCoroutines}}
{{^useCoroutines}}
val response = client.newCall(request).execute()
{{/useCoroutines}}

val accept = response.header(ContentType)?.substringBefore(";")?.lowercase(Locale.US)

Expand Down

0 comments on commit 569acbc

Please sign in to comment.