@@ -41,11 +41,13 @@ import com.jetbrains.rd.util.ConcurrentHashMap
41
41
import com.jetbrains.rd.util.URI
42
42
import com.jetbrains.rd.util.lifetime.Lifetime
43
43
import com.jetbrains.rd.util.lifetime.LifetimeDefinition
44
+ import com.jetbrains.rd.util.threading.coroutines.launch
44
45
import io.gitpod.gitpodprotocol.api.entities.WorkspaceInstance
45
46
import io.gitpod.jetbrains.gateway.common.GitpodConnectionHandleFactory
46
47
import io.gitpod.jetbrains.icons.GitpodIcons
47
48
import kotlinx.coroutines.*
48
49
import kotlinx.coroutines.future.await
50
+ import java.awt.Component
49
51
import java.net.URL
50
52
import java.net.http.HttpClient
51
53
import java.net.http.HttpRequest
@@ -71,6 +73,17 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
71
73
private val jacksonMapper = jacksonObjectMapper()
72
74
.configure(DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false )
73
75
76
+
77
+ private fun showTimedOutDialogDialog (workspaceId : String , detail : String? ) {
78
+ val title = " Workspace Timed Out"
79
+ val message = " Your workspace $workspaceId has timed out${if (detail.isNullOrBlank()) " " else " : $detail " } ."
80
+ val okButton = Messages .getOkButton()
81
+ val options = arrayOf(okButton)
82
+ val defaultIndex = 0
83
+ val icon = Messages .getInformationIcon()
84
+ Messages .showDialog(message, title, options, defaultIndex, icon)
85
+ }
86
+
74
87
override suspend fun connect (
75
88
parameters : Map <String , String >,
76
89
requestor : ConnectionRequestor
@@ -188,6 +201,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
188
201
var thinClientJob: Job ? = null
189
202
190
203
var lastUpdate: WorkspaceInstance ? = null
204
+ var canceledByGitpod = false
191
205
try {
192
206
for (update in updates) {
193
207
try {
@@ -255,8 +269,8 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
255
269
statusMessage.text = " "
256
270
}
257
271
}
258
-
259
272
if (update.status.phase == " stopping" || update.status.phase == " stopped" ) {
273
+ canceledByGitpod = true
260
274
thinClientJob?.cancel()
261
275
thinClient?.close()
262
276
}
@@ -295,9 +309,41 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
295
309
SshHostTunnelConnector (credentials),
296
310
URI (joinLinkResp.joinLink)
297
311
)
312
+ var triggeredClientClosed = false
298
313
clientHandle.clientClosed.advise(connectionLifetime) {
299
- application.invokeLater {
300
- connectionLifetime.terminate()
314
+ // Been canceled by user
315
+ if (! canceledByGitpod) {
316
+ connectionLifetime.launch {
317
+ // Delay for 5 seconds to see if thinClient could be terminated in time
318
+ // Then we don't see error dialog from Gateway
319
+ delay(5000 )
320
+ application.invokeLater {
321
+ connectionLifetime.terminate()
322
+ }
323
+ }
324
+ return @advise
325
+ }
326
+ if (triggeredClientClosed) {
327
+ return @advise
328
+ }
329
+ triggeredClientClosed = true
330
+ // Wait until workspace is stopped
331
+ suspend fun waitUntilStopped (): Boolean {
332
+ while (lastUpdate.status.phase != " stopped" ) {
333
+ delay(1000 )
334
+ }
335
+ return true
336
+ }
337
+ // Check if it's timed out, if so, show timed out dialog
338
+ connectionLifetime.launch {
339
+ val isInStoppedPhase = waitUntilStopped()
340
+ val isTimedOut = isInStoppedPhase && phaseMessage.text == " Timed Out"
341
+ application.invokeLater {
342
+ if (isTimedOut) {
343
+ showTimedOutDialogDialog(connectParams.resolvedWorkspaceId, lastUpdate.status.conditions.timeout)
344
+ }
345
+ connectionLifetime.terminate()
346
+ }
301
347
}
302
348
}
303
349
clientHandle.onClientPresenceChanged.advise(connectionLifetime) {
0 commit comments