Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7bed8d9

Browse files
committedMay 22, 2024··
Fix coroutines when running from File > Remote Development
For whatever reason, cs.launch does not work and you have to pass the modality state. Without this state, they do not launch until after the remote development window is closed. Using that from a background process fails, however (something about only being able to access from EDT), so instead of starting/stopping the poll there, I just always keep it running in the background (and it just does nothing when there is no client). For the re-invoking of the token window, I removed the launch entirely. Could probably use invokeLater() or something but this seems fine?
1 parent 3eadac2 commit 7bed8d9

File tree

4 files changed

+58
-33
lines changed

4 files changed

+58
-33
lines changed
 

‎CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
## Unreleased
66

7+
### Fixed
8+
9+
- Polling and workspace action buttons when running from File > Remote
10+
Development within a local IDE.
11+
712
## 2.11.6 - 2024-05-08
813

914
### Fixed

‎gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pluginGroup=com.coder.gateway
44
pluginName=coder-gateway
55
# SemVer format -> https://semver.org
6-
pluginVersion=2.11.6
6+
pluginVersion=2.11.7
77
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
88
# for insight into build numbers and IntelliJ Platform versions.
99
pluginSinceBuild=233.6745

‎src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import com.intellij.icons.AllIcons
2323
import com.intellij.ide.BrowserUtil
2424
import com.intellij.openapi.Disposable
2525
import com.intellij.openapi.actionSystem.AnActionEvent
26+
import com.intellij.openapi.application.ModalityState
27+
import com.intellij.openapi.application.asContextElement
2628
import com.intellij.openapi.components.service
2729
import com.intellij.openapi.diagnostic.Logger
2830
import com.intellij.openapi.project.DumbAwareAction
@@ -57,6 +59,7 @@ import kotlinx.coroutines.withContext
5759
import java.awt.Component
5860
import java.awt.Dimension
5961
import java.util.Locale
62+
import java.util.UUID
6063
import javax.swing.JComponent
6164
import javax.swing.event.DocumentEvent
6265

@@ -77,6 +80,7 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
7780
private val settings = service<CoderSettingsService>()
7881
private val recentConnectionsService = service<CoderRecentWorkspaceConnectionsService>()
7982
private val cs = CoroutineScope(Dispatchers.Main)
83+
private val jobs: MutableMap<UUID, Job> = mutableMapOf()
8084

8185
private val recentWorkspacesContentPanel = JBScrollPane()
8286

@@ -209,9 +213,19 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
209213
CoderIcons.RUN,
210214
) {
211215
override fun actionPerformed(e: AnActionEvent) {
212-
withoutNull(workspaceWithAgent, deployment?.client) { ws, client ->
213-
client.startWorkspace(ws.workspace)
214-
cs.launch { fetchWorkspaces() }
216+
withoutNull(workspaceWithAgent?.workspace, deployment?.client) { workspace, client ->
217+
jobs[workspace.id]?.cancel()
218+
jobs[workspace.id] =
219+
cs.launch(ModalityState.current().asContextElement()) {
220+
withContext(Dispatchers.IO) {
221+
try {
222+
client.startWorkspace(workspace)
223+
fetchWorkspaces()
224+
} catch (e: Exception) {
225+
logger.error("Could not start workspace ${workspace.name}", e)
226+
}
227+
}
228+
}
215229
}
216230
}
217231
},
@@ -230,9 +244,19 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
230244
CoderIcons.STOP,
231245
) {
232246
override fun actionPerformed(e: AnActionEvent) {
233-
withoutNull(workspaceWithAgent, deployment?.client) { ws, client ->
234-
client.stopWorkspace(ws.workspace)
235-
cs.launch { fetchWorkspaces() }
247+
withoutNull(workspaceWithAgent?.workspace, deployment?.client) { workspace, client ->
248+
jobs[workspace.id]?.cancel()
249+
jobs[workspace.id] =
250+
cs.launch(ModalityState.current().asContextElement()) {
251+
withContext(Dispatchers.IO) {
252+
try {
253+
client.stopWorkspace(workspace)
254+
fetchWorkspaces()
255+
} catch (e: Exception) {
256+
logger.error("Could not stop workspace ${workspace.name}", e)
257+
}
258+
}
259+
}
236260
}
237261
}
238262
},
@@ -348,9 +372,10 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
348372

349373
logger.info("Starting poll loop")
350374
poller =
351-
cs.launch {
375+
cs.launch(ModalityState.current().asContextElement()) {
352376
while (isActive) {
353377
if (recentWorkspacesContentPanel.isShowing) {
378+
logger.info("View still visible; fetching workspaces")
354379
fetchWorkspaces()
355380
} else {
356381
logger.info("View not visible; aborting poll")
@@ -413,9 +438,10 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
413438
// check for visibility if you want to avoid work while the panel is not
414439
// displaying.
415440
override fun dispose() {
416-
logger.info("Disposing recent view")
417441
cs.cancel()
418442
poller?.cancel()
443+
jobs.forEach { it.value.cancel() }
444+
jobs.clear()
419445
}
420446

421447
companion object {

‎src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import com.intellij.ide.BrowserUtil
2929
import com.intellij.ide.util.PropertiesComponent
3030
import com.intellij.openapi.actionSystem.AnAction
3131
import com.intellij.openapi.actionSystem.AnActionEvent
32+
import com.intellij.openapi.application.ModalityState
33+
import com.intellij.openapi.application.asContextElement
3234
import com.intellij.openapi.components.service
3335
import com.intellij.openapi.diagnostic.Logger
3436
import com.intellij.openapi.rd.util.launchUnderBackgroundProgress
@@ -302,13 +304,13 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
302304
withoutNull(client, tableOfWorkspaces.selectedObject?.workspace) { c, workspace ->
303305
jobs[workspace.id]?.cancel()
304306
jobs[workspace.id] =
305-
cs.launch {
307+
cs.launch(ModalityState.current().asContextElement()) {
306308
withContext(Dispatchers.IO) {
307309
try {
308310
c.startWorkspace(workspace)
309311
loadWorkspaces()
310312
} catch (e: Exception) {
311-
logger.error("Could not start workspace ${workspace.name}, reason: $e")
313+
logger.error("Could not start workspace ${workspace.name}", e)
312314
}
313315
}
314316
}
@@ -326,7 +328,7 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
326328
withoutNull(client, tableOfWorkspaces.selectedObject?.workspace) { c, workspace ->
327329
jobs[workspace.id]?.cancel()
328330
jobs[workspace.id] =
329-
cs.launch {
331+
cs.launch(ModalityState.current().asContextElement()) {
330332
withContext(Dispatchers.IO) {
331333
try {
332334
// Stop the workspace first if it is running.
@@ -374,7 +376,7 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
374376
loadWorkspaces()
375377
}
376378
} catch (e: Exception) {
377-
logger.error("Could not update workspace ${workspace.name}, reason: $e")
379+
logger.error("Could not update workspace ${workspace.name}", e)
378380
}
379381
}
380382
}
@@ -392,13 +394,13 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
392394
withoutNull(client, tableOfWorkspaces.selectedObject?.workspace) { c, workspace ->
393395
jobs[workspace.id]?.cancel()
394396
jobs[workspace.id] =
395-
cs.launch {
397+
cs.launch(ModalityState.current().asContextElement()) {
396398
withContext(Dispatchers.IO) {
397399
try {
398400
c.stopWorkspace(workspace)
399401
loadWorkspaces()
400402
} catch (e: Exception) {
401-
logger.error("Could not stop workspace ${workspace.name}, reason: $e")
403+
logger.error("Could not stop workspace ${workspace.name}", e)
402404
}
403405
}
404406
}
@@ -426,13 +428,12 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
426428
* Authorize the client and start polling for workspaces if we can.
427429
*/
428430
fun init() {
429-
// If we already have a client, start polling. Otherwise try to set one
431+
// After each poll, the workspace list will be updated.
432+
triggerWorkspacePolling()
433+
// If we already have a client, we are done. Otherwise try to set one
430434
// up from storage or config and automatically connect. Place the
431435
// values in the fields, so they can be seen and edited if necessary.
432-
if (client != null && cliManager != null) {
433-
// If there is a client then the fields are already filled.
434-
triggerWorkspacePolling(true)
435-
} else {
436+
if (client == null || cliManager == null) {
436437
// Try finding a URL and matching token to use.
437438
val lastUrl = appPropertiesService.getValue(CODER_URL_KEY)
438439
val lastToken = appPropertiesService.getValue(SESSION_TOKEN_KEY)
@@ -565,8 +566,6 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
565566
cliManager = null
566567
client = null
567568

568-
stop()
569-
570569
// Authenticate and load in a background process with progress.
571570
return LifetimeDefinition().launchUnderBackgroundProgress(
572571
CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.cli.downloader.dialog.title"),
@@ -609,7 +608,6 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
609608

610609
this.indicator.text = "Retrieving workspaces..."
611610
loadWorkspaces()
612-
triggerWorkspacePolling(false)
613611
} catch (e: Exception) {
614612
if (isCancellation(e)) {
615613
tfUrlComment?.text =
@@ -640,30 +638,26 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
640638
logger.error(msg, e)
641639

642640
if (e is APIResponseException && e.isUnauthorized && onAuthFailure != null) {
643-
cs.launch { onAuthFailure.invoke() }
641+
onAuthFailure.invoke()
644642
}
645643
}
646644
}
647645
}
648646
}
649647

650648
/**
651-
* Start polling for workspace changes. Throw if there is an existing
652-
* poller and it has not been stopped.
649+
* Start polling for workspace changes if not already started.
653650
*/
654-
private fun triggerWorkspacePolling(fetchNow: Boolean) {
651+
private fun triggerWorkspacePolling() {
655652
if (poller?.isActive == true) {
656653
logger.info("Refusing to start already-started poller")
657654
return
658655
}
659656
poller =
660-
cs.launch {
661-
if (fetchNow) {
662-
loadWorkspaces()
663-
}
657+
cs.launch(ModalityState.current().asContextElement()) {
664658
while (isActive) {
665-
delay(5000)
666659
loadWorkspaces()
660+
delay(5000)
667661
}
668662
}
669663
}
@@ -738,7 +732,7 @@ class CoderWorkspacesStepView : CoderWizardStep<CoderWorkspacesStepSelection>(
738732
logger.info("Retrieving the workspaces took: ${timeAfterRequestingWorkspaces - timeBeforeRequestingWorkspaces} millis")
739733
return@withContext ams
740734
} catch (e: Exception) {
741-
logger.error("Could not retrieve workspaces for ${clientNow.me.username} on ${clientNow.url}. Reason: $e")
735+
logger.error("Could not retrieve workspaces for ${clientNow.me.username} on ${clientNow.url}", e)
742736
emptySet()
743737
}
744738
}

0 commit comments

Comments
 (0)
Please sign in to comment.