Skip to content

Commit

Permalink
wip: kotlin foundation
Browse files Browse the repository at this point in the history
  • Loading branch information
aallam authored and Mouaad Aallam committed Mar 14, 2023
1 parent b205ccf commit d808425
Show file tree
Hide file tree
Showing 56 changed files with 751 additions and 421 deletions.
19 changes: 19 additions & 0 deletions clients/algoliasearch-client-kotlin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Gradle
.gradle
gradlew.bat
build
local.properties
reports
build

# IntelliJ IDEA
.idea
*.iml
*.ipl
*.iws
classes/
idea-classes/
coverage-error.log

# Java
*.hprof
27 changes: 25 additions & 2 deletions clients/algoliasearch-client-kotlin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import com.vanniktech.maven.publish.MavenPublishBaseExtension
import com.diffplug.gradle.spotless.SpotlessExtension
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent.*

@Suppress("DSL_SCOPE_VIOLATION")
plugins {
alias(libs.plugins.kotlin.multiplaform) apply false
alias(libs.plugins.kotlinx.serialization) apply false
Expand All @@ -8,6 +11,26 @@ plugins {
alias(libs.plugins.spotless) apply false
}

subprojects {
apply(plugin = "com.diffplug.spotless")
configure<SpotlessExtension> {
kotlin {
target("**/*.kt")
trimTrailingWhitespace()
endWithNewline()
}
}

tasks.withType<Test> {
testLogging {
events(STARTED, PASSED, SKIPPED, FAILED)
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = false
}
}
}


tasks.register<Delete>("clean") {
delete(rootProject.buildDir)
delete(rootProject.buildDir)
}
94 changes: 24 additions & 70 deletions clients/algoliasearch-client-kotlin/client/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,80 +1,34 @@
import com.diffplug.gradle.spotless.SpotlessExtension
import org.jetbrains.kotlin.konan.target.HostManager

plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
id("com.vanniktech.maven.publish")
id("com.diffplug.spotless")
id("binary-compatibility-validator")
kotlin("multiplatform")
kotlin("plugin.serialization")
id("com.vanniktech.maven.publish")
id("com.diffplug.spotless")
id("binary-compatibility-validator")
}

kotlin {
explicitApi()
jvm {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
testRuns["test"].executionTask.configure {
useJUnit()
testLogging {
events("failed")
setExceptionFormat("full")
}
}
}
explicitApi()
jvm()

sourceSets {
all {
languageSettings.apply {
optIn("kotlin.RequiresOptIn")
optIn("kotlinx.coroutines.ExperimentalCoroutinesApi")
}
}
val commonMain by getting {
dependencies {
api(libs.ktor.client.core)
api(libs.kotlinx.serialization.json)
implementation(libs.ktor.client.logging)
implementation(libs.ktor.client.serialization.json)
implementation(libs.ktor.client.content.negotiation)
}
}
val commonTest by getting {
dependencies {
implementation(libs.kotlin.test.common)
implementation(libs.kotlin.test.annotations.common)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.ktor.client.mock)
}
}
val jvmMain by getting
val jvmTest by getting {
dependencies {
implementation(libs.kotlin.test.junit)
implementation(libs.ktor.client.apache)
implementation(libs.ktor.client.okhttp)
}
}
}
}
if (HostManager.hostIsMac) {
ios()
}

tasks {
val copyTemplates by registering(type = Copy::class) {
from("src/commonMain/templates")
val outputDir = "$buildDir/generated/sources/templates/kotlin/main"
into(outputDir)
val version = project.extensions.extraProperties["VERSION_NAME"] as String // require clean build
expand("projectVersion" to version)
filteringCharset = "UTF-8"
sourceSets {
all {
languageSettings.optIn("kotlinx.coroutines.ExperimentalCoroutinesApi")
}

kotlin.sourceSets.commonMain.get().kotlin.srcDir(copyTemplates)
}

configure<SpotlessExtension> {
kotlin {
target("**/*.kt")
trimTrailingWhitespace()
endWithNewline()
val commonMain by getting {
dependencies {
api(libs.ktor.client.core)
api(libs.kotlinx.serialization.json)
implementation(libs.ktor.client.logging)
implementation(libs.ktor.client.serialization.json)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.kotlin.datetime)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.algolia.search.configuration

/**
* Indicate whether the HTTP call performed is of type [Read] (GET) or [Write] (POST, PUT ..).
* Used to determined which timeout duration to use.
*/
public enum class CallType {
Read,
Write
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.algolia.search.configuration

import com.algolia.search.logging.LogLevel
import com.algolia.search.logging.Logger
import com.algolia.search.transport.RequestOptions
import io.ktor.client.HttpClient
import io.ktor.client.HttpClientConfig
import io.ktor.client.engine.HttpClientEngine

/**
* Configuration used by a client.
*/
public interface Configuration {

/**
* The timeout for each request when performing write operations (POST, PUT ..).
*/
public val writeTimeout: Long

/**
* The timeout for each request when performing read operations (GET).
*/
public val readTimeout: Long

/**
* [LogLevel] to display in the console.
*/
public val logLevel: LogLevel

/**
* List of hosts and back-up host used to perform a custom retry logic.
*/
public val hosts: List<Host>

/**
* An optional [HttpClientConfig<*>] used by Ktor for advanced HttpClient httpClientConfig.
*/
public val httpClientConfig: ((HttpClientConfig<*>) -> Unit)?

/**
* An optional [HttpClientEngine] to specify which HttpEngine should be used by Ktor.
*/
public val engine: HttpClientEngine?

/**
* The [HttpClient] used by Ktor to perform http request.
*/
public val httpClient: HttpClient

/**
* Default headers that should be applied to every request.
*/
public val defaultHeaders: Map<String, String>?

public val logger: Logger
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.algolia.search.configuration

import com.algolia.search.model.APIKey
import com.algolia.search.model.ApplicationID

/**
* Configuration used by a client for authenticated request.
*/
public interface Credentials {

/**
* [ApplicationID] to target. Is passed as a HTTP header.
*/
public val applicationID: ApplicationID

/**
* [APIKey] for a given [ApplicationID]. Is passed as a HTTP header.
* To maintain security, never use your Admin [APIKey] on your front end or share it with anyone.
* In your front end, use the Search-only [APIKey] or any other key that has search-only rights.
*/
public val apiKey: APIKey
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.algolia.search.configuration

/**
* @param url The url to target.
* @param callType Whether this host should be used for [CallType.Read] or [CallType.Write] requests.
*/
public data class Host(
public val url: String,
public val callType: CallType? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.algolia.search.configuration

/**
* Get algolia client user agent.
*/
public fun clientUserAgent(version: String): String = "Algolia for Kotlin ($version)"
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.algolia.search.exception

/**
* Algolia runtime exception.
*
* @param message the detail message
* @param cause the cause of the exception
*/
public sealed class AlgoliaRuntimeException(
message: String? = null,
cause: Throwable? = null
) : RuntimeException(message, cause)

/**
* Exception thrown when an error occurs during API requests.
*
* @param message the detail message
* @param cause the cause of the exception
*/
public class AlgoliaClientException(
message: String? = null,
cause: Throwable? = null
) : AlgoliaRuntimeException(message, cause)

/**
* Exception thrown in case of API failure.
*
* @param message the detail message
* @param cause the cause of the exception
* @param httpErrorCode
*/
public class AlgoliaApiException(
message: String? = null,
cause: Throwable? = null,
public val httpErrorCode: Int? = null
) : AlgoliaRuntimeException(message, cause)

/**
* Exception thrown when all hosts are unreachable.
* When several errors occurred, use the last one as the cause for the returned exception.
*
* @param exceptions list of thrown exceptions
*/
public class UnreachableHostsException(
public val exceptions: List<Throwable>,
) : AlgoliaRuntimeException("Error(s) while processing the retry strategy", exceptions.last())
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.algolia.search.exception

/**
* This exception is thrown when an illegal empty [List] is encountered.
*/
public class EmptyListException(name: String) : Exception("$name must not be an empty list.")
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.algolia.search.exception

/**
* This exception is thrown when an illegal empty [String] is encountered.
*/
public class EmptyStringException(name: String) : IllegalArgumentException("$name must not have an empty string value.")
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.algolia.search.exception.internal

import com.algolia.search.exception.AlgoliaApiException
import com.algolia.search.exception.AlgoliaClientException
import com.algolia.search.exception.AlgoliaRuntimeException
import io.ktor.client.plugins.ResponseException

/**
* Coerce a Throwable to a [AlgoliaClientException].
*/
internal fun Throwable.asClientException(): AlgoliaClientException {
return AlgoliaClientException(message = message, cause = this)
}

/**
* Coerce a [ResponseException] to a [AlgoliaRuntimeException].
*/
internal fun ResponseException.asApiException(): AlgoliaApiException {
return AlgoliaApiException(message = message, cause = this, httpErrorCode = response.status.value)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.algolia.search.logging

/**
* Http client logging log level.
*/
public enum class LogLevel {
All, Headers, Body, Info, None
}
Loading

0 comments on commit d808425

Please sign in to comment.