-
Notifications
You must be signed in to change notification settings - Fork 17
/
FoojayApi.kt
111 lines (94 loc) · 3.99 KB
/
FoojayApi.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package org.gradle.toolchains.foojay
import org.gradle.api.GradleException
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JvmImplementation
import org.gradle.jvm.toolchain.JvmVendorSpec
import org.gradle.platform.Architecture
import org.gradle.platform.OperatingSystem
import java.io.BufferedReader
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URI
import java.net.URL
import java.net.URLEncoder
import java.nio.charset.StandardCharsets.UTF_8
import java.util.concurrent.TimeUnit.SECONDS
class FoojayApi {
val CONNECT_TIMEOUT = SECONDS.toMillis(10).toInt()
val READ_TIMEOUT = SECONDS.toMillis(20).toInt()
val SCHEMA = "https"
val ENDPOINT_ROOT = "api.foojay.io/disco/v3.0"
val DISTRIBUTIONS_ENDPOIT = "$ENDPOINT_ROOT/distributions"
val PACKAGES_ENDPOINT = "$ENDPOINT_ROOT/packages"
val distributions = mutableListOf<Distribution>()
fun toUri(
version: JavaLanguageVersion,
vendor: JvmVendorSpec,
implementation: JvmImplementation,
operatingSystem: OperatingSystem,
architecture: Architecture
): URI? {
val distribution = match(vendor, implementation, version) ?: return null
val downloadPackage = match(distribution.api_parameter, version, operatingSystem, architecture) ?: return null
return downloadPackage.links.pkg_download_redirect
}
internal fun match(vendor: JvmVendorSpec, implementation: JvmImplementation, version: JavaLanguageVersion): Distribution? {
fetchDistributionsIfMissing()
return match(distributions, vendor, implementation, version)
}
private fun fetchDistributionsIfMissing() {
if (distributions.isEmpty()) {
val con = createConnection(
DISTRIBUTIONS_ENDPOIT,
mapOf("include_versions" to "true", "include_synonyms" to "true")
)
val json = readResponse(con)
con.disconnect()
distributions.addAll(parseDistributions(json))
}
}
internal fun match(distributionName: String, version: JavaLanguageVersion, operatingSystem: OperatingSystem, architecture: Architecture): Package? {
val con = createConnection(
PACKAGES_ENDPOINT,
mapOf(
"jdk_version" to "${version.asInt()}",
"distro" to distributionName,
"operating_system" to map(operatingSystem),
"latest" to "available",
"directly_downloadable" to "true",
)
)
val json = readResponse(con)
con.disconnect()
val packages = parsePackages(json)
return match(packages, architecture)
}
private fun createConnection(endpoint: String, parameters: Map<String, String>): HttpURLConnection {
val url = URL("$SCHEMA://$endpoint?${toParameterString(parameters)}")
val con = url.openConnection() as HttpURLConnection
con.setRequestProperty("Content-Type", "application/json")
con.requestMethod = "GET"
con.connectTimeout = CONNECT_TIMEOUT
con.readTimeout = READ_TIMEOUT
return con
}
private fun toParameterString(params: Map<String, String>): String {
val result = StringBuilder()
for (param in params) {
result.append(URLEncoder.encode(param.key, UTF_8))
result.append("=")
result.append(URLEncoder.encode(param.value, UTF_8))
result.append("&")
}
if (params.isNotEmpty()) result.delete(result.length - 1, result.length)
return result.toString()
}
private fun readResponse(con: HttpURLConnection): String {
val status = con.responseCode
if (status != HttpURLConnection.HTTP_OK) {
throw GradleException("Requesting vendor list failed: ${readContent(con.errorStream)}")
}
return readContent(con.inputStream)
}
private fun readContent(stream: InputStream) = stream.bufferedReader().use(BufferedReader::readText)
}