jdks - download XZ packed JSON (less CDN traffic), handle exceptions from the Network

IDEA-225308

GitOrigin-RevId: b335c60657852bdf76cdf6a6bda8134622dfc44d
This commit is contained in:
Eugene Petrenko
2019-10-24 10:32:20 +02:00
committed by intellij-monorepo-bot
parent 856fdacfdb
commit 7a0cf3c3dd
2 changed files with 66 additions and 35 deletions

View File

@@ -71,6 +71,7 @@
<orderEntry type="library" name="jackson" level="project" /> <orderEntry type="library" name="jackson" level="project" />
<orderEntry type="library" name="jackson-databind" level="project" /> <orderEntry type="library" name="jackson-databind" level="project" />
<orderEntry type="library" name="jackson-module-kotlin" level="project" /> <orderEntry type="library" name="jackson-module-kotlin" level="project" />
<orderEntry type="library" name="xz" level="project" />
</component> </component>
<component name="copyright"> <component name="copyright">
<Base> <Base>

View File

@@ -21,6 +21,8 @@ import com.intellij.ui.components.dialog
import com.intellij.ui.layout.* import com.intellij.ui.layout.*
import com.intellij.util.Consumer import com.intellij.util.Consumer
import com.intellij.util.io.HttpRequests import com.intellij.util.io.HttpRequests
import org.tukaani.xz.XZInputStream
import java.io.ByteArrayInputStream
import javax.swing.DefaultComboBoxModel import javax.swing.DefaultComboBoxModel
import javax.swing.JComponent import javax.swing.JComponent
@@ -87,51 +89,75 @@ class JDKDownloader {
if (!registry.isNullOrBlank()) return registry if (!registry.isNullOrBlank()) return registry
//let's use CDN URL in once it'd be established //let's use CDN URL in once it'd be established
return "https://buildserver.labs.intellij.net/guestAuth/repository/download/ijplatform_master_Service_GenerateJDKsJson/lasest.lastSuccessful/feed.zip!/jdks.json" return "https://buildserver.labs.intellij.net/guestAuth/repository/download/ijplatform_master_Service_GenerateJDKsJson/lasest.lastSuccessful/feed.zip!/jdks.json.xz"
} }
fun downloadModel(progress: ProgressIndicator?): JDKDownloadModel { fun downloadModel(progress: ProgressIndicator?, feedUrl : String = this.feedUrl): JDKDownloadModel {
//the file is ~15k, in-memory only via JSON tree, no caches needed //we download XZ packed version of the data (several KBs packed, several dozen KBs unpacked) and process it in-memory
val rawData = HttpRequests.request(feedUrl).forceHttps(true).readString(progress) val rawData = try {
val tree = om.readTree(rawData) as? ObjectNode ?: error("Unexpected JSON data") HttpRequests
val items = tree["jdks"] as? ArrayNode ?: error("`jdks` element is missing") .request(feedUrl)
.connectTimeout(5_000)
val expectedOS = when { .readTimeout(5_000)
SystemInfo.isWindows -> "windows" .forceHttps(true)
SystemInfo.isMac -> "mac" .throwStatusCodeException(true)
SystemInfo.isLinux -> "linux" .readBytes(progress)
else -> error("Unsupported OS") .unXZ()
} catch (t: Throwable) {
LOG.warn("Failed to download and process the JDKs list from $feedUrl. ${t.message}", t)
return JDKDownloadModel.errorModel("Failed to download and process the JDKs list from $feedUrl")
} }
val result = mutableListOf<JDKDownloadItem>() try {
for (item in items.filterIsInstance<ObjectNode>()) { val tree = om.readTree(rawData) as? ObjectNode ?: error("Unexpected JSON data")
val vendor = item["vendor"]?.asText() ?: continue val items = tree["jdks"] as? ArrayNode ?: error("`jdks` element is missing")
val version = item["jdk_version"]?.asText() ?: continue
val packages = item["packages"] as? ArrayNode ?: continue
val pkg = packages.filterIsInstance<ObjectNode>().singleOrNull { it["os"]?.asText() == expectedOS } ?: continue
val arch = pkg["arch"]?.asText() ?: continue
val fileType = pkg["package"]?.asText() ?: continue
val url = pkg["url"]?.asText() ?: continue
val size = pkg["size"]?.asLong() ?: continue
val sha256 = pkg["sha256"]?.asText() ?: continue
result += JDKDownloadItem(vendor = vendor, val expectedOS = when {
version = version, SystemInfo.isWindows -> "windows"
arch = arch, SystemInfo.isMac -> "mac"
fileType = fileType, SystemInfo.isLinux -> "linux"
url = url, else -> error("Unsupported OS")
size = size, }
sha256 = sha256)
val result = mutableListOf<JDKDownloadItem>()
for (item in items.filterIsInstance<ObjectNode>()) {
val vendor = item["vendor"]?.asText() ?: continue
val version = item["jdk_version"]?.asText() ?: continue
val packages = item["packages"] as? ArrayNode ?: continue
val pkg = packages.filterIsInstance<ObjectNode>().singleOrNull { it["os"]?.asText() == expectedOS } ?: continue
val arch = pkg["arch"]?.asText() ?: continue
val fileType = pkg["package"]?.asText() ?: continue
val url = pkg["url"]?.asText() ?: continue
val size = pkg["size"]?.asLong() ?: continue
val sha256 = pkg["sha256"]?.asText() ?: continue
result += JDKDownloadItem(vendor = vendor,
version = version,
arch = arch,
fileType = fileType,
url = url,
size = size,
sha256 = sha256)
}
return JDKDownloadModel.validModel(result)
} catch (t: Throwable) {
LOG.warn("Failed to parse downloaded JDKs list from $feedUrl. ${t.message}", t)
return JDKDownloadModel.errorModel("Failed to parse downloaded JDKs list")
} }
return JDKDownloadModel(result)
} }
} }
data class JDKDownloadModel( class JDKDownloadModel private constructor(
val feedError: String?,
val items: List<JDKDownloadItem> val items: List<JDKDownloadItem>
) ) {
companion object {
fun errorModel(error: String) = JDKDownloadModel(feedError = error, items = listOf())
fun validModel(items: List<JDKDownloadItem>) = JDKDownloadModel(feedError = null, items = items)
}
}
data class JDKDownloadItem( data class JDKDownloadItem(
val vendor: String, val vendor: String,
@@ -142,3 +168,7 @@ data class JDKDownloadItem(
val size: Long, val size: Long,
val sha256: String val sha256: String
) )
private fun ByteArray.unXZ() = ByteArrayInputStream(this).use { input ->
XZInputStream(input).use { it.readBytes() }
}