diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/MarketplaceRequests.kt b/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/MarketplaceRequests.kt index acbb5b7bf6ef..b67827aad1ac 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/MarketplaceRequests.kt +++ b/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/MarketplaceRequests.kt @@ -14,7 +14,6 @@ import com.intellij.ide.util.PropertiesComponent import com.intellij.internal.statistic.eventLog.fus.MachineIdManager import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.PathManager -import com.intellij.openapi.application.PermanentInstallationID import com.intellij.openapi.application.impl.ApplicationInfoImpl import com.intellij.openapi.components.serviceOrNull import com.intellij.openapi.diagnostic.Logger @@ -26,7 +25,6 @@ import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginAdver import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginAdvertiserService.Companion.marketplaceIdeCodes import com.intellij.openapi.util.BuildNumber import com.intellij.openapi.util.IntellijInternalApi -import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.TimeoutCachedValue import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.util.PlatformUtils @@ -36,6 +34,7 @@ import com.intellij.util.io.HttpRequests import com.intellij.util.io.RequestBuilder import com.intellij.util.io.computeDetached import com.intellij.util.io.write +import com.intellij.util.system.OS import com.intellij.util.ui.IoErrorText import com.intellij.util.withQuery import kotlinx.coroutines.CoroutineScope @@ -125,7 +124,37 @@ class MarketplaceRequests(private val coroutineScope: CoroutineScope) : PluginIn @JvmStatic @JvmOverloads fun getLastCompatiblePluginUpdate( - ids: Set, + allIds: Set, + buildNumber: BuildNumber? = null, + throwExceptions: Boolean = false + ): List { + val chunks = mutableListOf>() + chunks.add(mutableListOf()) + + val maxLength = 7000 // 8k minus safety gap + var currentLength = 0 + val pluginXmlIdsLength = "&pluginXmlId=".length + + for (id in allIds) { + val adder = id.idString.length + pluginXmlIdsLength + val newLength = currentLength + adder + if (newLength > maxLength) { + chunks.add(mutableListOf(id)) + currentLength = adder + } + else { + currentLength = newLength + chunks.last().add(id) + } + } + + return chunks.flatMap { + loadLastCompatiblePluginsUpdate(it, buildNumber, throwExceptions) + } + } + + private fun loadLastCompatiblePluginsUpdate( + ids: Collection, buildNumber: BuildNumber? = null, throwExceptions: Boolean = false ): List { @@ -134,32 +163,31 @@ class MarketplaceRequests(private val coroutineScope: CoroutineScope) : PluginIn return emptyList() } - var url = URI(MarketplaceUrls.getSearchCompatibleUpdatesUrl()) - val os = URLEncoder.encode(SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION, CharsetToolkit.UTF8) - val uid = PermanentInstallationID.get() + var url = URI(MarketplaceUrls.getSearchPluginsUpdatesUrl()) + val os = URLEncoder.encode(OS.CURRENT.name + " " + OS.CURRENT.version, CharsetToolkit.UTF8) val machineId = MachineIdManager.getAnonymizedMachineId("JetBrainsUpdates") .takeIf { PropertiesComponent.getInstance().getBoolean(UpdateChecker.MACHINE_ID_DISABLED_PROPERTY, false) } val query = buildString { append("build=${ApplicationInfoImpl.orFromPluginCompatibleBuild(buildNumber)}") append("&os=$os") - append("&uuid=$uid") if (machineId != null) { - append("&machineId=$machineId") + append("&mid=$machineId") + } + for (id in ids) { + append("&pluginXmlId=${URLEncoder.encode(id.idString, CharsetToolkit.UTF8)}") } } val urlString = url.withQuery(query).toString() - val data = objectMapper.writeValueAsString(CompatibleUpdateRequest(ids, buildNumber)) - return HttpRequests.post(urlString, HttpRequests.JSON_CONTENT_TYPE).run { - productNameAsUserAgent() - throwStatusCodeException(throwExceptions) - connect { - it.write(data) + return HttpRequests.request(urlString) + .accept(HttpRequests.JSON_CONTENT_TYPE) + .productNameAsUserAgent() + .throwStatusCodeException(throwExceptions) + .connect { objectMapper.readValue(it.inputStream, object : TypeReference>() {}) } - } } catch (e: Exception) { LOG.infoOrDebug("Can not get compatible updates from Marketplace", e) @@ -367,7 +395,7 @@ class MarketplaceRequests(private val coroutineScope: CoroutineScope) : PluginIn return Files.newInputStream(pluginXmlIdsFile).use(::parseXmlIds) } } - catch (ignore: IOException) { + catch (_: IOException) { } return null } @@ -656,7 +684,7 @@ class MarketplaceRequests(private val coroutineScope: CoroutineScope) : PluginIn } } catch (_: IOException) { } - // can't find/read jb plugins xml ids cache file, schedule reload + // can't find/read jb plugins XML ids cache file, schedule reload schedulePluginIdsUpdate() return null } @@ -749,7 +777,7 @@ class MarketplaceRequests(private val coroutineScope: CoroutineScope) : PluginIn } /** - * NB!: any previous tuners set by {@link RequestBuilder#tuner} will be overwritten by this call + * NB!: this call will overwrite any previous tuners set by {@link RequestBuilder#tuner} */ fun RequestBuilder.setHeadersViaTuner(): RequestBuilder { return if (LoadingState.COMPONENTS_REGISTERED.isOccurred) { @@ -773,7 +801,7 @@ private fun loadETagForFile(file: Path): String { LOG.warn("Can't load ETag from '" + eTagFile + "'. Unexpected number of lines: " + lines.size) Files.deleteIfExists(eTagFile) } - catch (ignore: NoSuchFileException) { + catch (_: NoSuchFileException) { } catch (e: IOException) { LOG.warn("Can't load ETag from '$eTagFile'", e) diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/utils/MarketplaceUrls.kt b/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/utils/MarketplaceUrls.kt index a4c643d6b0b0..e06351e0169f 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/utils/MarketplaceUrls.kt +++ b/platform/platform-impl/src/com/intellij/ide/plugins/marketplace/utils/MarketplaceUrls.kt @@ -49,8 +49,11 @@ object MarketplaceUrls { "${getPluginManagerUrl()}/api/search/aggregation/$field" ).addParameters(mapOf("build" to IDE_BUILD_FOR_REQUEST)) + @Deprecated("Use getSearchPluginsUpdatesUrl() instead") fun getSearchCompatibleUpdatesUrl() = Urls.newFromEncoded("${getPluginManagerUrl()}/api/search/compatibleUpdates").toExternalForm() + fun getSearchPluginsUpdatesUrl() = Urls.newFromEncoded("${getPluginManagerUrl()}/api/search/updates/compatible").toExternalForm() + fun getSearchNearestUpdate() = Urls.newFromEncoded("${getPluginManagerUrl()}/api/search/updates/nearest").toExternalForm() fun getSearchPluginsUrl(query: String, count: Int, includeIncompatible: Boolean): Url {