@@ -12,6 +12,7 @@ import com.intellij.ide.BrowserUtil
12
12
import com.intellij.openapi.components.service
13
13
import com.intellij.openapi.diagnostic.thisLogger
14
14
import com.intellij.openapi.progress.ProgressManager
15
+ import com.intellij.openapi.ui.Messages
15
16
import com.intellij.remote.RemoteCredentialsHolder
16
17
import com.intellij.ssh.AskAboutHostKey
17
18
import com.intellij.ssh.OpenSshLikeHostKeyVerifier
@@ -30,6 +31,7 @@ import com.jetbrains.gateway.api.*
30
31
import com.jetbrains.gateway.ssh.ClientOverSshTunnelConnector
31
32
import com.jetbrains.gateway.ssh.SshHostTunnelConnector
32
33
import com.jetbrains.gateway.thinClientLink.ThinClientHandle
34
+ import com.jetbrains.rd.util.ConcurrentHashMap
33
35
import com.jetbrains.rd.util.URI
34
36
import com.jetbrains.rd.util.lifetime.Lifetime
35
37
import io.gitpod.gitpodprotocol.api.entities.WorkspaceInstance
@@ -49,7 +51,7 @@ import kotlin.coroutines.coroutineContext
49
51
50
52
@Suppress(" UnstableApiUsage" , " OPT_IN_USAGE" )
51
53
class GitpodConnectionProvider : GatewayConnectionProvider {
52
-
54
+ private val activeConnections = ConcurrentHashMap < String , Boolean >()
53
55
private val gitpod = service<GitpodConnectionService >()
54
56
55
57
private val httpClient = HttpClient .newBuilder()
@@ -59,6 +61,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
59
61
private val jacksonMapper = jacksonObjectMapper()
60
62
.configure(DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false )
61
63
64
+
62
65
override suspend fun connect (
63
66
parameters : Map <String , String >,
64
67
requestor : ConnectionRequestor
@@ -74,6 +77,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
74
77
parameters[" workspaceId" ]!! ,
75
78
parameters[" backendPort" ]
76
79
)
80
+
77
81
val client = gitpod.obtainClient(connectParams.gitpodHost)
78
82
val connectionLifetime = Lifetime .Eternal .createNested()
79
83
val updates = client.listenToWorkspace(connectionLifetime, connectParams.workspaceId)
@@ -144,6 +148,24 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
144
148
connectionPanel.repaint()
145
149
}
146
150
151
+ val connectionKeyId = " ${connectParams.gitpodHost} -${connectParams.workspaceId} -${connectParams.backendPort} "
152
+
153
+ if (activeConnections.containsKey(connectionKeyId)) {
154
+ val message = " You are trying to connect to a workspace that has a session already open"
155
+ val title = " Oops"
156
+ val okButton = Messages .getOkButton()
157
+ val options = arrayOf(okButton)
158
+ val defaultIndex = 0
159
+ val icon = Messages .getWarningIcon()
160
+ Messages .showDialog(message, title, options, defaultIndex, icon)
161
+
162
+ val errMessage = " A connection to the same workspace already exists: $connectionKeyId "
163
+ thisLogger().warn(errMessage)
164
+ throw IllegalStateException (errMessage)
165
+ } else {
166
+ activeConnections.putIfAbsent(connectionKeyId, true )
167
+ }
168
+
147
169
GlobalScope .launch {
148
170
var thinClient: ThinClientHandle ? = null
149
171
var thinClientJob: Job ? = null
@@ -219,6 +241,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
219
241
val sshHostUrl = URL (update.ideUrl.replace(update.workspaceId, " ${update.workspaceId} .ssh" ));
220
242
val hostKeys = resolveHostKeys(updatedIdeUrl, connectParams)
221
243
if (hostKeys.isNullOrEmpty()) {
244
+ activeConnections.remove(connectionKeyId)
222
245
setErrorMessage(" ${connectParams.gitpodHost} installation does not allow SSH access, public keys cannot be found" )
223
246
return @launch
224
247
}
@@ -227,6 +250,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
227
250
resolveCredentials(sshHostUrl, update.workspaceId, ownerToken, hostKeys)
228
251
val joinLink = resolveJoinLink(updatedIdeUrl, ownerToken, connectParams)
229
252
if (joinLink.isNullOrEmpty()) {
253
+ activeConnections.remove(connectionKeyId)
230
254
setErrorMessage(" failed to fetch JetBrains Gateway Join Link." )
231
255
return @launch
232
256
}
@@ -239,6 +263,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
239
263
clientHandle.clientClosed.advise(connectionLifetime) {
240
264
application.invokeLater {
241
265
connectionLifetime.terminate()
266
+ activeConnections.remove(connectionKeyId)
242
267
}
243
268
}
244
269
clientHandle.onClientPresenceChanged.advise(connectionLifetime) {
0 commit comments