User: rednesto Date: 16 Jul 24 14:58 Revision: 8537ff03ee4f537fd6fcc5d01afc33222c5b284f Summary: Migrate creator versions download to coroutines TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=9478&personal=false Index: src/main/kotlin/creator/custom/CreatorContext.kt =================================================================== --- src/main/kotlin/creator/custom/CreatorContext.kt (revision da8086f5e32f197e4542a2f6676dd5a221769898) +++ src/main/kotlin/creator/custom/CreatorContext.kt (revision 8537ff03ee4f537fd6fcc5d01afc33222c5b284f) @@ -21,11 +21,37 @@ package com.demonwav.mcdev.creator.custom import com.demonwav.mcdev.creator.custom.types.CreatorProperty +import com.demonwav.mcdev.creator.modalityState import com.intellij.ide.util.projectWizard.WizardContext +import com.intellij.openapi.application.EDT +import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.application.asContextElement import com.intellij.openapi.observable.properties.PropertyGraph +import com.intellij.util.namedChildScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlin.coroutines.CoroutineContext data class CreatorContext( val graph: PropertyGraph, val properties: Map>, val wizardContext: WizardContext, -) + val scope: CoroutineScope +) { + val modalityState: ModalityState + get() = wizardContext.modalityState + + val coroutineContext: CoroutineContext + get() = modalityState.asContextElement() + + /** + * The CoroutineContext to use when a change has to be made to the creator UI + */ + val uiContext: CoroutineContext + get() = Dispatchers.EDT + coroutineContext + + /** + * A general purpose scope dependent of the main creator scope, cancelled when the creator is closed. + */ + fun childScope(name: String): CoroutineScope = scope.namedChildScope(name) +} Index: src/main/kotlin/creator/custom/CustomPlatformStep.kt =================================================================== --- src/main/kotlin/creator/custom/CustomPlatformStep.kt (revision da8086f5e32f197e4542a2f6676dd5a221769898) +++ src/main/kotlin/creator/custom/CustomPlatformStep.kt (revision 8537ff03ee4f537fd6fcc5d01afc33222c5b284f) @@ -91,6 +91,7 @@ parent: NewProjectWizardStep, ) : AbstractNewProjectWizardStep(parent) { + val creatorScope = TemplateService.instance.scope("MinecraftDev Creator") val creatorUiScope = TemplateService.instance.scope("MinecraftDev Creator UI") val templateRepos = MinecraftSettings.instance.creatorTemplateRepos @@ -126,10 +127,11 @@ private var hasTemplateErrors: Boolean = true private var properties = mutableMapOf>() - private var creatorContext = CreatorContext(propertyGraph, properties, context) + private var creatorContext = CreatorContext(propertyGraph, properties, context, creatorScope) init { Disposer.register(context.disposable) { + creatorScope.cancel("The creator got disposed") creatorUiScope.cancel("The creator got disposed") } } Index: src/main/kotlin/creator/custom/types/ArchitecturyVersionsCreatorProperty.kt =================================================================== --- src/main/kotlin/creator/custom/types/ArchitecturyVersionsCreatorProperty.kt (revision da8086f5e32f197e4542a2f6676dd5a221769898) +++ src/main/kotlin/creator/custom/types/ArchitecturyVersionsCreatorProperty.kt (revision 8537ff03ee4f537fd6fcc5d01afc33222c5b284f) @@ -49,8 +49,7 @@ import javax.swing.DefaultComboBoxModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.swing.Swing +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class ArchitecturyVersionsCreatorProperty( @@ -280,7 +279,7 @@ updateArchitecturyApiVersions() } - downloadVersions { + downloadVersions(context) { val fabricVersions = fabricVersions if (fabricVersions != null) { loaderVersionModel.removeAllElements() @@ -433,40 +432,39 @@ private var fabricApiVersions: FabricApiVersions? = null private var architecturyVersions: ArchitecturyVersion? = null - private fun downloadVersions(completeCallback: () -> Unit) { + private fun downloadVersions(context: CreatorContext, completeCallback: () -> Unit) { if (hasDownloadedVersions) { completeCallback() return } - application.executeOnPooledThread { - runBlocking { + val scope = context.childScope("ArchitecturyVersionsCreatorProperty") + scope.launch(Dispatchers.Default) { - awaitAll( - asyncIO { ForgeVersion.downloadData().also { forgeVersions = it } }, - asyncIO { NeoForgeVersion.downloadData().also { neoForgeVersions = it } }, - asyncIO { FabricVersions.downloadData().also { fabricVersions = it } }, - asyncIO { - collectMavenVersions( - "https://maven.architectury.dev/dev/architectury/architectury-loom/maven-metadata.xml" - ).also { - loomVersions = it - .mapNotNull(SemanticVersion::tryParse) - .sortedDescending() - } - }, - asyncIO { FabricApiVersions.downloadData().also { fabricApiVersions = it } }, - asyncIO { ArchitecturyVersion.downloadData().also { architecturyVersions = it } }, - ) + awaitAll( + asyncIO { ForgeVersion.downloadData().also { forgeVersions = it } }, + asyncIO { NeoForgeVersion.downloadData().also { neoForgeVersions = it } }, + asyncIO { FabricVersions.downloadData().also { fabricVersions = it } }, + asyncIO { + collectMavenVersions( + "https://maven.architectury.dev/dev/architectury/architectury-loom/maven-metadata.xml" + ).also { + loomVersions = it + .mapNotNull(SemanticVersion::tryParse) + .sortedDescending() + } + }, + asyncIO { FabricApiVersions.downloadData().also { fabricApiVersions = it } }, + asyncIO { ArchitecturyVersion.downloadData().also { architecturyVersions = it } }, + ) - hasDownloadedVersions = true + hasDownloadedVersions = true - withContext(Dispatchers.Swing) { + withContext(context.uiContext) { - completeCallback() - } - } - } - } + completeCallback() + } + } + } + } - } class Factory : CreatorPropertyFactory { Index: src/main/kotlin/creator/custom/types/FabricVersionsCreatorProperty.kt =================================================================== --- src/main/kotlin/creator/custom/types/FabricVersionsCreatorProperty.kt (revision da8086f5e32f197e4542a2f6676dd5a221769898) +++ src/main/kotlin/creator/custom/types/FabricVersionsCreatorProperty.kt (revision 8537ff03ee4f537fd6fcc5d01afc33222c5b284f) @@ -41,13 +41,11 @@ import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.bindItem import com.intellij.ui.dsl.builder.bindSelected -import com.intellij.util.application import com.intellij.util.ui.AsyncProcessIcon import javax.swing.DefaultComboBoxModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.swing.Swing +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class FabricVersionsCreatorProperty( @@ -220,7 +218,7 @@ updateFabricApiVersions() } - downloadVersion { + downloadVersion(context) { val fabricVersions = fabricVersions if (fabricVersions != null) { loaderVersionModel.removeAllElements() @@ -307,35 +305,34 @@ private var loomVersions: List? = null private var fabricApiVersions: FabricApiVersions? = null - private fun downloadVersion(uiCallback: () -> Unit) { + private fun downloadVersion(context: CreatorContext, uiCallback: () -> Unit) { if (hasDownloadedVersions) { uiCallback() return } - application.executeOnPooledThread { - runBlocking { + val scope = context.childScope("FabricVersionsCreatorProperty") + scope.launch(Dispatchers.Default) { - awaitAll( - asyncIO { FabricVersions.downloadData().also { fabricVersions = it } }, - asyncIO { - collectMavenVersions( - "https://maven.fabricmc.net/net/fabricmc/fabric-loom/maven-metadata.xml" - ).mapNotNull(SemanticVersion::tryParse) - .sortedDescending() - .also { loomVersions = it } - }, - asyncIO { FabricApiVersions.downloadData().also { fabricApiVersions = it } }, - ) + awaitAll( + asyncIO { FabricVersions.downloadData().also { fabricVersions = it } }, + asyncIO { + collectMavenVersions( + "https://maven.fabricmc.net/net/fabricmc/fabric-loom/maven-metadata.xml" + ).mapNotNull(SemanticVersion::tryParse) + .sortedDescending() + .also { loomVersions = it } + }, + asyncIO { FabricApiVersions.downloadData().also { fabricApiVersions = it } }, + ) - hasDownloadedVersions = true + hasDownloadedVersions = true - withContext(Dispatchers.Swing) { + withContext(context.uiContext) { - uiCallback() - } - } - } - } + uiCallback() + } + } + } + } - } class Factory : CreatorPropertyFactory { Index: src/main/kotlin/creator/custom/types/ForgeVersionsCreatorProperty.kt =================================================================== --- src/main/kotlin/creator/custom/types/ForgeVersionsCreatorProperty.kt (revision da8086f5e32f197e4542a2f6676dd5a221769898) +++ src/main/kotlin/creator/custom/types/ForgeVersionsCreatorProperty.kt (revision 8537ff03ee4f537fd6fcc5d01afc33222c5b284f) @@ -36,12 +36,10 @@ import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.RightGap import com.intellij.ui.dsl.builder.bindItem -import com.intellij.util.application import com.intellij.util.ui.AsyncProcessIcon import javax.swing.DefaultComboBoxModel import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.swing.Swing +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class ForgeVersionsCreatorProperty( @@ -148,7 +146,7 @@ } } - downloadVersions { + downloadVersions(context) { reloadMinecraftVersions() loadingVersionsProperty.set(false) @@ -186,25 +184,24 @@ private var forgeVersion: ForgeVersion? = null - private fun downloadVersions(uiCallback: () -> Unit) { + private fun downloadVersions(context: CreatorContext, uiCallback: () -> Unit) { if (hasDownloadedVersions) { uiCallback() return } - application.executeOnPooledThread { - runBlocking { + val scope = context.childScope("ForgeVersionsCreatorProperty") + scope.launch(Dispatchers.IO) { - forgeVersion = ForgeVersion.downloadData() + forgeVersion = ForgeVersion.downloadData() - hasDownloadedVersions = true + hasDownloadedVersions = true - withContext(Dispatchers.Swing) { + withContext(context.uiContext) { - uiCallback() - } - } - } - } + uiCallback() + } + } + } + } - } class Factory : CreatorPropertyFactory { override fun create( Index: src/main/kotlin/creator/custom/types/MavenArtifactVersionCreatorProperty.kt =================================================================== --- src/main/kotlin/creator/custom/types/MavenArtifactVersionCreatorProperty.kt (revision da8086f5e32f197e4542a2f6676dd5a221769898) +++ src/main/kotlin/creator/custom/types/MavenArtifactVersionCreatorProperty.kt (revision 8537ff03ee4f537fd6fcc5d01afc33222c5b284f) @@ -32,12 +32,10 @@ import com.intellij.ui.ComboboxSpeedSearch import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.bindItem -import com.intellij.util.application import com.intellij.util.ui.AsyncProcessIcon import java.util.concurrent.ConcurrentHashMap import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.swing.Swing +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class MavenArtifactVersionCreatorProperty( @@ -110,6 +108,7 @@ } downloadVersions( + context, // The key might be a bit too unique, but that'll do the job descriptor.name + "@" + descriptor.hashCode(), sourceUrl, @@ -127,6 +126,7 @@ private var versionsCache = ConcurrentHashMap>() private fun downloadVersions( + context: CreatorContext, key: String, url: String, rawVersionFilter: (String) -> Boolean, @@ -143,26 +143,25 @@ return } - application.executeOnPooledThread { - runBlocking { - val versions = collectMavenVersions(url) + val scope = context.childScope("MavenArtifactVersionCreatorProperty") + scope.launch(Dispatchers.Default) { + val versions = withContext(Dispatchers.IO) { collectMavenVersions(url) } - .asSequence() - .filter(rawVersionFilter) - .mapNotNull(SemanticVersion::tryParse) - .filter(versionFilter) - .sortedDescending() - .take(limit) - .toList() + .asSequence() + .filter(rawVersionFilter) + .mapNotNull(SemanticVersion::tryParse) + .filter(versionFilter) + .sortedDescending() + .take(limit) + .toList() - versionsCache[cacheKey] = versions + versionsCache[cacheKey] = versions - withContext(Dispatchers.Swing) { + withContext(context.uiContext) { - uiCallback(versions) - } - } - } - } + uiCallback(versions) + } + } + } + } - } class Factory : CreatorPropertyFactory { Index: src/main/kotlin/creator/custom/types/NeoForgeVersionsCreatorProperty.kt =================================================================== --- src/main/kotlin/creator/custom/types/NeoForgeVersionsCreatorProperty.kt (revision da8086f5e32f197e4542a2f6676dd5a221769898) +++ src/main/kotlin/creator/custom/types/NeoForgeVersionsCreatorProperty.kt (revision 8537ff03ee4f537fd6fcc5d01afc33222c5b284f) @@ -39,13 +39,11 @@ import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.RightGap import com.intellij.ui.dsl.builder.bindItem -import com.intellij.util.application import com.intellij.util.ui.AsyncProcessIcon import javax.swing.DefaultComboBoxModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.swing.Swing +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class NeoForgeVersionsCreatorProperty( @@ -135,7 +133,7 @@ } val mcVersionFilter = descriptor.parameters?.get("mcVersionFilter") as? String - downloadVersion(mcVersionFilter) { + downloadVersion(context, mcVersionFilter) { val mcVersions = mcVersions ?: return@downloadVersion mcVersionsModel.removeAllElements() @@ -164,40 +162,39 @@ private var mdVersion: NeoModDevVersion? = null private var mcVersions: List? = null - private fun downloadVersion(mcVersionFilter: String?, uiCallback: () -> Unit) { + private fun downloadVersion(context: CreatorContext, mcVersionFilter: String?, uiCallback: () -> Unit) { if (hasDownloadedVersions) { uiCallback() return } - application.executeOnPooledThread { - runBlocking { + val scope = context.childScope("NeoForgeVersionsCreatorProperty") + scope.launch(Dispatchers.Default) { - awaitAll( - asyncIO { NeoForgeVersion.downloadData().also { nfVersion = it } }, - asyncIO { NeoGradleVersion.downloadData().also { ngVersion = it } }, - asyncIO { NeoModDevVersion.downloadData().also { mdVersion = it } }, - ) + awaitAll( + asyncIO { NeoForgeVersion.downloadData().also { nfVersion = it } }, + asyncIO { NeoGradleVersion.downloadData().also { ngVersion = it } }, + asyncIO { NeoModDevVersion.downloadData().also { mdVersion = it } }, + ) - mcVersions = nfVersion?.sortedMcVersions?.let { mcVersion -> - if (mcVersionFilter != null) { - mcVersion.filter { version -> - val conditionProps = mapOf("MC_VERSION" to version) - TemplateEvaluator.condition(conditionProps, mcVersionFilter).getOrDefault(true) - } - } else { - mcVersion - } - } + mcVersions = nfVersion?.sortedMcVersions?.let { mcVersion -> + if (mcVersionFilter != null) { + mcVersion.filter { version -> + val conditionProps = mapOf("MC_VERSION" to version) + TemplateEvaluator.condition(conditionProps, mcVersionFilter).getOrDefault(true) + } + } else { + mcVersion + } + } - hasDownloadedVersions = true + hasDownloadedVersions = true - withContext(Dispatchers.Swing) { + withContext(context.uiContext) { - uiCallback() - } - } - } - } + uiCallback() + } + } + } + } - } class Factory : CreatorPropertyFactory { override fun create( Index: src/main/kotlin/creator/custom/types/ParchmentCreatorProperty.kt =================================================================== --- src/main/kotlin/creator/custom/types/ParchmentCreatorProperty.kt (revision da8086f5e32f197e4542a2f6676dd5a221769898) +++ src/main/kotlin/creator/custom/types/ParchmentCreatorProperty.kt (revision 8537ff03ee4f537fd6fcc5d01afc33222c5b284f) @@ -34,11 +34,9 @@ import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.bindItem import com.intellij.ui.dsl.builder.bindSelected -import com.intellij.util.application import javax.swing.DefaultComboBoxModel import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.swing.Swing +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class ParchmentCreatorProperty( @@ -167,7 +165,7 @@ refreshVersionsLists() } - downloadVersions { + downloadVersions(context) { refreshVersionsLists() val minecraftVersion = getPlatformMinecraftVersion() @@ -248,26 +246,25 @@ private var allParchmentVersions: List? = null - private fun downloadVersions(uiCallback: () -> Unit) { + private fun downloadVersions(context: CreatorContext, uiCallback: () -> Unit) { if (hasDownloadedVersions) { uiCallback() return } - application.executeOnPooledThread { - runBlocking { + val scope = context.childScope("ParchmentCreatorProperty") + scope.launch(Dispatchers.IO) { - allParchmentVersions = ParchmentVersion.downloadData() - .sortedByDescending(ParchmentVersion::parchmentVersion) + allParchmentVersions = ParchmentVersion.downloadData() + .sortedByDescending(ParchmentVersion::parchmentVersion) - hasDownloadedVersions = true + hasDownloadedVersions = true - withContext(Dispatchers.Swing) { + withContext(context.uiContext) { - uiCallback() - } - } - } - } + uiCallback() + } + } + } + } - } class Factory : CreatorPropertyFactory { override fun create(