@@ -5,17 +5,23 @@ import com.fasterxml.jackson.databind.ObjectMapper
55import com.fasterxml.jackson.databind.SerializationFeature
66import com.fasterxml.jackson.dataformat.xml.XmlMapper
77import com.fasterxml.jackson.module.kotlin.registerKotlinModule
8+ import java.io.File
89import kotlin.io.path.Path
910import kotlin.io.path.readLines
1011import kotlin.time.Duration.Companion.seconds
1112import kotlin.time.toJavaDuration
13+ import okhttp3.Cache
1214import okhttp3.Dispatcher
15+ import okhttp3.Interceptor
1316import okhttp3.OkHttpClient
17+ import okhttp3.logging.HttpLoggingInterceptor
1418import org.koin.core.KoinApplication
1519import org.koin.core.qualifier.named
1620import org.koin.dsl.module
21+ import org.slf4j.LoggerFactory
1722import retrofit2.Retrofit
1823import retrofit2.converter.jackson.JacksonConverterFactory
24+ import retrofit2.converter.wire.WireConverterFactory
1925import retrofit2.create
2026import xyz.block.artifactswap.core.config.ArtifactSwapConfigHolder
2127import xyz.block.artifactswap.core.eventstream.Eventstream
@@ -26,18 +32,67 @@ import xyz.block.artifactswap.core.network.ArtifactoryService
2632private val UNAUTHENTICATED_HTTP_METHODS = listOf (" GET" , " HEAD" )
2733
2834internal fun artifactoryNetworkModule () = module {
35+ // HTTP cache for OkHttp client (10MB)
36+ // It's small because we only cache error responses from the repo
37+ single<Cache > {
38+ val cacheDirectory = File (System .getProperty(" java.io.tmpdir" ), " artifactswap-cache" )
39+ Cache (cacheDirectory, 10L * 1024L * 1024L )
40+ }
41+
42+ single<HttpLoggingInterceptor > {
43+ val logger = LoggerFactory .getLogger(" http" )
44+ HttpLoggingInterceptor { message -> logger.trace(message) }
45+ .apply { level = HttpLoggingInterceptor .Level .BASIC }
46+ }
47+
48+ // Interceptor that caches only 404 responses for 1 hour and prevents caching of successful
49+ // responses.
50+ // Successful artifact downloads are implicitly cached in the local .m2 repository.
51+ // Missing artifacts are expensive to query from the repo backend and should be cached.
52+ single<Interceptor >(named(" cache404Interceptor" )) {
53+ Interceptor { chain ->
54+ val response = chain.proceed(chain.request())
55+
56+ when (response.code) {
57+ // Cache 404 responses for 1 hour
58+ 404 -> {
59+ response
60+ .newBuilder()
61+ .header(" Cache-Control" , " public, max-age=3600, immutable" )
62+ .removeHeader(" Pragma" )
63+ .removeHeader(" Expires" )
64+ .build()
65+ }
66+ // Prevent caching of successful responses (artifacts are cached in local .m2 repo)
67+ in 200 .. 299 -> {
68+ response
69+ .newBuilder()
70+ .header(" Cache-Control" , " no-store" )
71+ .removeHeader(" Pragma" )
72+ .removeHeader(" Expires" )
73+ .build()
74+ }
75+ // Don't modify other response codes
76+ else -> response
77+ }
78+ }
79+ }
80+
2981 single<OkHttpClient >(named(" artifactoryClient" )) {
3082 OkHttpClient .Builder ()
83+ .cache(get<Cache >())
3184 .retryOnConnectionFailure(true )
32- .connectTimeout(30 .seconds.toJavaDuration())
33- .readTimeout(30 .seconds.toJavaDuration())
34- .callTimeout(30 .seconds.toJavaDuration())
85+ .connectTimeout(5 .seconds.toJavaDuration())
86+ .readTimeout(10 .seconds.toJavaDuration())
87+ .callTimeout(10 .seconds.toJavaDuration())
3588 .dispatcher(
3689 Dispatcher ().apply {
3790 maxRequestsPerHost = 128
3891 maxRequests = 512
3992 }
4093 )
94+ .addInterceptor(get<HttpLoggingInterceptor >())
95+ .addNetworkInterceptor(get<Interceptor >(named(" cache404Interceptor" )))
4196 .addInterceptor { chain ->
4297 // GET/HEAD methods don't require authentication
4398 if (chain.request().method !in UNAUTHENTICATED_HTTP_METHODS ) {
@@ -95,15 +150,15 @@ internal fun analyticsNetworkModule() = module {
95150 single<EventstreamService > {
96151 val httpClient =
97152 OkHttpClient .Builder ()
98- .connectTimeout(30 , java.util.concurrent. TimeUnit . SECONDS )
99- .readTimeout(30 , java.util.concurrent. TimeUnit . SECONDS )
100- .writeTimeout(30 , java.util.concurrent. TimeUnit . SECONDS )
153+ .connectTimeout(5 .seconds.toJavaDuration() )
154+ .readTimeout(10 .seconds.toJavaDuration() )
155+ .writeTimeout(10 .seconds.toJavaDuration() )
101156 .build()
102157
103158 Retrofit .Builder ()
104159 .baseUrl(ArtifactSwapConfigHolder .instance.eventstreamBaseUrl)
105160 .client(httpClient)
106- .addConverterFactory(retrofit2.converter.wire. WireConverterFactory .create())
161+ .addConverterFactory(WireConverterFactory .create())
107162 .build()
108163 .create<EventstreamService >()
109164 }
0 commit comments