Skip to content

Commit

Permalink
feat: support connection and socket timeout configurations (#481)
Browse files Browse the repository at this point in the history
  • Loading branch information
mohnoor94 authored Mar 11, 2024
1 parent 542a9a7 commit 6bb2e6d
Show file tree
Hide file tree
Showing 23 changed files with 211 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,7 @@ abstract class BaseRapidClient(
override val httpClient: HttpClient
get() = _httpClient

/**
* A [BaseRapidClient] builder.
*
* @property key The API key to use for authentication.
* @property secret The API secret to use for authentication.
* @property endpoint The API endpoint to use for requests.
* @property requestTimeout The request timeout to be used.
* @property maskedLoggingHeaders The headers to be masked in logging.
* @property maskedLoggingBodyFields The body fields to be masked in logging.
*/
/** A [BaseRapidClient] builder. */
@Suppress("unused", "UnnecessaryAbstractClass") // This is used by the generated SDK clients.
abstract class Builder<SELF : com.expediagroup.sdk.core.client.BaseRapidClient.Builder<SELF>> : com.expediagroup.sdk.core.client.Client.Builder<SELF>()
abstract class Builder<SELF : Builder<SELF>> : Client.Builder<SELF>()
}
80 changes: 72 additions & 8 deletions core/src/main/kotlin/com/expediagroup/sdk/core/client/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ abstract class Client(
val endpoint: String = configurationProvider.endpoint ?: fireMissingConfigurationIssue(ConfigurationName.ENDPOINT)
val authEndpoint: String = configurationProvider.authEndpoint ?: fireMissingConfigurationIssue(ConfigurationName.AUTH_ENDPOINT)
val requestTimeout: Long = configurationProvider.requestTimeout ?: fireMissingConfigurationIssue(ConfigurationName.REQUEST_TIMEOUT_MILLIS)
val connectionTimeout: Long = configurationProvider.connectionTimeout ?: fireMissingConfigurationIssue(ConfigurationName.CONNECTION_TIMEOUT_MILLIS)
val socketTimeout: Long = configurationProvider.socketTimeout ?: fireMissingConfigurationIssue(ConfigurationName.SOCKET_TIMEOUT_MILLIS)
val maskedLoggingHeaders: Set<String> = configurationProvider.maskedLoggingHeaders ?: setOf()
val maskedLoggingBodyFields: Set<String> = configurationProvider.maskedLoggingBodyFields ?: setOf()

Expand All @@ -107,7 +109,7 @@ abstract class Client(
use(AuthenticationPlugin).with(authenticationConfiguration)
use(DefaultRequestPlugin).with(DefaultRequestConfiguration.from(httpClientConfig, endpoint))
use(EncodingPlugin).with(EncodingConfiguration.from(httpClientConfig))
use(HttpTimeoutPlugin).with(HttpTimeoutConfiguration.from(httpClientConfig, requestTimeout))
use(HttpTimeoutPlugin).with(HttpTimeoutConfiguration.from(httpClientConfig, requestTimeout, connectionTimeout, socketTimeout))
use(ExceptionHandlingPlugin).with(ExceptionHandlingConfiguration.from(httpClientConfig))
}

Expand Down Expand Up @@ -138,20 +140,48 @@ abstract class Client(

/**
* A [Client] builder.
*
* @property key The API key to use for authentication.
* @property secret The API secret to use for authentication.
* @property endpoint The API endpoint to use for requests.
* @property requestTimeout The request timeout to be used.
* @property maskedLoggingHeaders The headers to be masked in logging.
* @property maskedLoggingBodyFields The body fields to be masked in logging.
*/
abstract class Builder<SELF : Builder<SELF>> {
/** Sets the API key to use for authentication. */
protected var key: String? = null

/** Sets the API secret to use for authentication. */
protected var secret: String? = null

/** Sets the API endpoint to use for requests. */
protected var endpoint: String? = null

/**
* Sets the request timeout in milliseconds.
*
* Request timeout is the time period from the start of the request to the completion of the response.
*
* Default is infinite - no timeout.
*/
protected var requestTimeout: Long? = null

/**
* Sets the connection timeout in milliseconds.
*
* Connection timeout is the time period from the start of the request to the establishment of the connection with the server.
*
* Default is 10 seconds (10000 milliseconds).
*/
protected var connectionTimeout: Long? = null

/**
* Sets the socket timeout in milliseconds.
*
* Socket timeout is the maximum period of inactivity between two consecutive data packets.
*
* Default is 15 seconds (15000 milliseconds).
*/
protected var socketTimeout: Long? = null

/** Sets tne body fields to be masked in logging. */
protected var maskedLoggingHeaders: Set<String>? = null

/** Sets tne body fields to be masked in logging. */
protected var maskedLoggingBodyFields: Set<String>? = null

/** Sets the API key to use for authentication.
Expand Down Expand Up @@ -181,17 +211,49 @@ abstract class Client(
*/
fun endpoint(endpoint: String): SELF {
this.endpoint = endpoint.adhereTo(Contract.TRAILING_SLASH)
log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.ENDPOINT, endpoint))
return self()
}

/**
* Sets the request timeout in milliseconds.
* Request timeout is the time period from the start of the request to the completion of the response.
* Default is infinite - no timeout.
*
* @param milliseconds The request timeout to be used.
* @return The [Builder] instance.
*/
fun requestTimeout(milliseconds: Long): SELF {
this.requestTimeout = milliseconds
log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.REQUEST_TIMEOUT_MILLIS, milliseconds.toString()))
return self()
}

/**
* Sets the connection timeout in milliseconds.
* Connection timeout is the time period from the start of the request to the establishment of the connection with the server.
* Default is 10 seconds (10000 milliseconds).
*
* @param milliseconds The connection timeout to be used.
* @return The [Builder] instance.
*/
fun connectionTimeout(milliseconds: Long): SELF {
this.connectionTimeout = milliseconds
log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.CONNECTION_TIMEOUT_MILLIS, milliseconds.toString()))
return self()
}

/**
* Sets the socket timeout in milliseconds.
* Socket timeout is the maximum period of inactivity between two consecutive data packets.
* Default is 15 seconds (15000 milliseconds).
*
* @param milliseconds The socket timeout to be used.
* @return The [Builder] instance.
*/
fun socketTimeout(milliseconds: Long): SELF {
this.socketTimeout = milliseconds
log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.SOCKET_TIMEOUT_MILLIS, milliseconds.toString()))
return self()
}

Expand All @@ -203,6 +265,7 @@ abstract class Client(
*/
fun maskedLoggingHeaders(vararg headers: String): SELF {
this.maskedLoggingHeaders = headers.toSet()
log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.MASKED_LOGGING_HEADERS, headers.joinToString()))
return self()
}

Expand All @@ -214,6 +277,7 @@ abstract class Client(
*/
fun maskedLoggingBodyFields(vararg fields: String): SELF {
this.maskedLoggingBodyFields = fields.toSet()
log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.MASKED_LOGGING_BODY_FIELDS, fields.joinToString()))
return self()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.expediagroup.sdk.core.configuration.collector.ConfigurationCollector
import com.expediagroup.sdk.core.configuration.provider.ConfigurationProvider
import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider
import com.expediagroup.sdk.core.plugin.authentication.strategy.AuthenticationStrategy
import com.expediagroup.sdk.core.plugin.logging.ExpediaGroupLoggerFactory
import io.ktor.client.HttpClient
import io.ktor.client.engine.HttpClientEngine

Expand All @@ -34,6 +35,10 @@ abstract class ExpediaGroupClient(
clientConfiguration: ExpediaGroupClientConfiguration,
httpClientEngine: HttpClientEngine = DEFAULT_HTTP_CLIENT_ENGINE
) : Client(namespace) {
companion object {
private val log = ExpediaGroupLoggerFactory.getLogger(this::class.java)
}

private val _configurationProvider: ConfigurationProvider =
ConfigurationCollector.create(
clientConfiguration.toProvider(),
Expand All @@ -51,19 +56,10 @@ abstract class ExpediaGroupClient(
override val httpClient: HttpClient
get() = _httpClient

/**
* An [ExpediaGroupClient] builder.
*
* @property key The API key to use for requests.
* @property secret The API secret to use for requests.
* @property endpoint The API endpoint to use for requests.
* @property authEndpoint The API auth endpoint to use for requests.
* @property requestTimeout The request timeout to be used.
* @property maskedLoggingHeaders The headers to be masked in logging.
* @property maskedLoggingBodyFields The body fields to be masked in logging.
*/
/** An [ExpediaGroupClient] builder. */
@Suppress("unused") // This is used by the generated SDK clients.
abstract class Builder<SELF : Builder<SELF>> : Client.Builder<SELF>() {
/** Sets the API auth endpoint to use for requests. */
protected var authEndpoint: String? = null

/** Sets the API auth endpoint to use for requests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ interface ClientConfiguration {
val secret: String?
val endpoint: String?
val requestTimeout: Long?
val connectionTimeout: Long?
val socketTimeout: Long?
val maskedLoggingHeaders: Set<String>?
val maskedLoggingBodyFields: Set<String>?

Expand All @@ -32,6 +34,8 @@ interface ClientConfiguration {
secret = secret,
endpoint = endpoint,
requestTimeout = requestTimeout,
connectionTimeout = connectionTimeout,
socketTimeout = socketTimeout,
maskedLoggingHeaders = maskedLoggingHeaders,
maskedLoggingBodyFields = maskedLoggingBodyFields
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import com.expediagroup.sdk.core.configuration.provider.RuntimeConfigurationProv
* @property secret The API secret to use for authentication.
* @property endpoint The API endpoint to use for requests.
* @property requestTimeout The request timeout to be used in milliseconds.
* @property connectionTimeout The connection timeout to be used in milliseconds.
* @property socketTimeout The socket timeout to be used in milliseconds.
* @property maskedLoggingHeaders The headers to be masked in logging.
* @property maskedLoggingBodyFields The body fields to be masked in logging.
* @property authEndpoint The API endpoint to use for authentication.
Expand All @@ -34,6 +36,8 @@ data class ExpediaGroupClientConfiguration(
override val secret: String? = null,
override val endpoint: String? = null,
override val requestTimeout: Long? = null,
override val connectionTimeout: Long? = null,
override val socketTimeout: Long? = null,
override val maskedLoggingHeaders: Set<String>? = null,
override val maskedLoggingBodyFields: Set<String>? = null,
val authEndpoint: String? = null
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import com.expediagroup.sdk.core.client.BaseRapidClient
* @property secret The API secret to use for authentication.
* @property endpoint The API endpoint to use for requests.
* @property requestTimeout The request timeout to be used in milliseconds.
* @property connectionTimeout The connection timeout to be used in milliseconds.
* @property socketTimeout The socket timeout to be used in milliseconds.
* @property maskedLoggingHeaders The headers to be masked in logging.
* @property maskedLoggingBodyFields The body fields to be masked in logging.
*/
Expand All @@ -32,6 +34,8 @@ data class RapidClientConfiguration(
override val secret: String? = null,
override val endpoint: String? = null,
override val requestTimeout: Long? = null,
override val connectionTimeout: Long? = null,
override val socketTimeout: Long? = null,
override val maskedLoggingHeaders: Set<String>? = null,
override val maskedLoggingBodyFields: Set<String>? = null
) : ClientConfiguration
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ package com.expediagroup.sdk.core.configuration.collector
import com.expediagroup.sdk.core.configuration.provider.ConfigurationProvider
import com.expediagroup.sdk.core.constant.ConfigurationName.AUTH_ENDPOINT
import com.expediagroup.sdk.core.constant.ConfigurationName.CONFIGURATION_COLLECTOR
import com.expediagroup.sdk.core.constant.ConfigurationName.CONNECTION_TIMEOUT_MILLIS
import com.expediagroup.sdk.core.constant.ConfigurationName.ENDPOINT
import com.expediagroup.sdk.core.constant.ConfigurationName.KEY
import com.expediagroup.sdk.core.constant.ConfigurationName.MASKED_LOGGING_BODY_FIELDS
import com.expediagroup.sdk.core.constant.ConfigurationName.MASKED_LOGGING_HEADERS
import com.expediagroup.sdk.core.constant.ConfigurationName.REQUEST_TIMEOUT_MILLIS
import com.expediagroup.sdk.core.constant.ConfigurationName.SECRET
import com.expediagroup.sdk.core.constant.ConfigurationName.SOCKET_TIMEOUT_MILLIS
import com.expediagroup.sdk.core.constant.provider.LoggingMessageProvider
import com.expediagroup.sdk.core.plugin.logging.ExpediaGroupLoggerFactory

Expand Down Expand Up @@ -60,6 +62,8 @@ internal class ConfigurationCollector private constructor(providers: Configurati
override val endpoint: String? = providers.firstWith { it.endpoint }.also { it?.log(ENDPOINT) }?.retrieve()
override val authEndpoint: String? = providers.firstWith { it.authEndpoint }.also { it?.log(AUTH_ENDPOINT) }?.retrieve()
override val requestTimeout: Long? = providers.firstWith { it.requestTimeout }.also { it?.log(REQUEST_TIMEOUT_MILLIS) }?.retrieve()
override val connectionTimeout: Long? = providers.firstWith { it.connectionTimeout }.also { it?.log(CONNECTION_TIMEOUT_MILLIS) }?.retrieve()
override val socketTimeout: Long? = providers.firstWith { it.socketTimeout }.also { it?.log(SOCKET_TIMEOUT_MILLIS) }?.retrieve()
override val maskedLoggingHeaders: Set<String>? = providers.firstWith { it.maskedLoggingHeaders }.also { it?.log(MASKED_LOGGING_HEADERS) }?.retrieve()
override val maskedLoggingBodyFields: Set<String>? = providers.firstWith { it.maskedLoggingBodyFields }.also { it?.log(MASKED_LOGGING_BODY_FIELDS) }?.retrieve()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,14 @@ interface ConfigurationProvider {
val authEndpoint: String?
get() = Constant.EMPTY_STRING

/** The timeout to use for API requests. */
/** The time period from the start of the request to the completion of the response. */
val requestTimeout: Long?
get() = Constant.TEN_SECONDS_IN_MILLIS

/** The time period from the start of the request to the establishment of the connection with the server. */
val connectionTimeout: Long?

/** The maximum period of inactivity between two consecutive data packets. */
val socketTimeout: Long?

/** The headers to be masked in logging. */
val maskedLoggingHeaders: Set<String>?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
package com.expediagroup.sdk.core.configuration.provider

import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.authEndpoint
import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.connectionTimeout
import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.endpoint
import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.name
import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.requestTimeout
import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.socketTimeout
import com.expediagroup.sdk.core.constant.Constant

/**
* Default configuration provider for ExpediaGroup.
Expand All @@ -27,9 +30,14 @@ import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfiguratio
* @property endpoint The API endpoint to use for requests.
* @property authEndpoint The API endpoint to use for authentication.
* @property requestTimeout The API response timeout to use for requests.
* @property connectionTimeout The connection timeout to be used in milliseconds.
* @property socketTimeout The socket timeout to be used in milliseconds.
*/
internal object ExpediaGroupConfigurationProvider : ConfigurationProvider {
override val name: String = "ExpediaGroup Configuration Provider"
override val endpoint: String = "https://api.expediagroup.com/"
override val authEndpoint: String = "${endpoint}identity/oauth2/v3/token/"
override val requestTimeout: Long = Constant.INFINITE_TIMEOUT
override val connectionTimeout: Long = Constant.TEN_SECONDS_IN_MILLIS
override val socketTimeout: Long = Constant.FIFTEEN_SECONDS_IN_MILLIS
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,26 @@
*/
package com.expediagroup.sdk.core.configuration.provider

import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.connectionTimeout
import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.endpoint
import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.name
import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.requestTimeout
import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.socketTimeout
import com.expediagroup.sdk.core.constant.Constant

/**
* Default configuration provider for Rapid.
*
* @property name The name of the provider.
* @property endpoint The API endpoint to use for requests.
* @property requestTimeout The API response timeout to use for requests.
* @property connectionTimeout The connection timeout to use for requests.
* @property socketTimeout The socket timeout to use for requests.
*/
internal object RapidConfigurationProvider : ConfigurationProvider {
override val name: String = "Rapid Configuration Provider"
override val endpoint: String = "https://api.ean.com/v3"
override val requestTimeout: Long = Constant.INFINITE_TIMEOUT
override val connectionTimeout: Long = Constant.TEN_SECONDS_IN_MILLIS
override val socketTimeout: Long = Constant.FIFTEEN_SECONDS_IN_MILLIS
}
Loading

0 comments on commit 6bb2e6d

Please sign in to comment.