@@ -12,6 +12,7 @@ import com.intellij.ide.BrowserUtil
1212import com.intellij.openapi.components.service
1313import com.intellij.openapi.diagnostic.thisLogger
1414import com.intellij.openapi.progress.ProgressManager
15+ import com.intellij.openapi.ui.Messages
1516import com.intellij.remote.RemoteCredentialsHolder
1617import com.intellij.ssh.AskAboutHostKey
1718import com.intellij.ssh.OpenSshLikeHostKeyVerifier
@@ -30,6 +31,7 @@ import com.jetbrains.gateway.api.*
3031import com.jetbrains.gateway.ssh.ClientOverSshTunnelConnector
3132import com.jetbrains.gateway.ssh.SshHostTunnelConnector
3233import com.jetbrains.gateway.thinClientLink.ThinClientHandle
34+ import com.jetbrains.rd.util.ConcurrentHashMap
3335import com.jetbrains.rd.util.URI
3436import com.jetbrains.rd.util.lifetime.Lifetime
3537import io.gitpod.gitpodprotocol.api.entities.WorkspaceInstance
@@ -49,7 +51,7 @@ import kotlin.coroutines.coroutineContext
4951
5052@Suppress(" UnstableApiUsage" , " OPT_IN_USAGE" )
5153class GitpodConnectionProvider : GatewayConnectionProvider {
52-
54+ private val activeConnections = ConcurrentHashMap < String , Boolean >()
5355 private val gitpod = service<GitpodConnectionService >()
5456
5557 private val httpClient = HttpClient .newBuilder()
@@ -58,7 +60,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
5860
5961 private val jacksonMapper = jacksonObjectMapper()
6062 .configure(DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false )
61-
63+
6264 override suspend fun connect (
6365 parameters : Map <String , String >,
6466 requestor : ConnectionRequestor
@@ -74,6 +76,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
7476 parameters[" workspaceId" ]!! ,
7577 parameters[" backendPort" ]
7678 )
79+
7780 val client = gitpod.obtainClient(connectParams.gitpodHost)
7881 val connectionLifetime = Lifetime .Eternal .createNested()
7982 val updates = client.listenToWorkspace(connectionLifetime, connectParams.workspaceId)
@@ -144,6 +147,24 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
144147 connectionPanel.repaint()
145148 }
146149
150+ val connectionKeyId = " ${connectParams.gitpodHost} -${connectParams.workspaceId} -${connectParams.backendPort} "
151+
152+ if (activeConnections.containsKey(connectionKeyId)) {
153+ val message = " You are trying to connect to a workspace that has a session already open"
154+ val title = " Oops"
155+ val okButton = Messages .getOkButton()
156+ val options = arrayOf(okButton)
157+ val defaultIndex = 0
158+ val icon = Messages .getWarningIcon()
159+ Messages .showDialog(message, title, options, defaultIndex, icon)
160+
161+ val errMessage = " A connection to the same workspace already exists: $connectionKeyId "
162+ thisLogger().warn(errMessage)
163+ throw IllegalStateException (errMessage)
164+ } else {
165+ activeConnections.putIfAbsent(connectionKeyId, true )
166+ }
167+
147168 GlobalScope .launch {
148169 var thinClient: ThinClientHandle ? = null
149170 var thinClientJob: Job ? = null
@@ -219,6 +240,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
219240 val sshHostUrl = URL (update.ideUrl.replace(update.workspaceId, " ${update.workspaceId} .ssh" ));
220241 val hostKeys = resolveHostKeys(updatedIdeUrl, connectParams)
221242 if (hostKeys.isNullOrEmpty()) {
243+ activeConnections.remove(connectionKeyId)
222244 setErrorMessage(" ${connectParams.gitpodHost} installation does not allow SSH access, public keys cannot be found" )
223245 return @launch
224246 }
@@ -227,6 +249,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
227249 resolveCredentials(sshHostUrl, update.workspaceId, ownerToken, hostKeys)
228250 val joinLink = resolveJoinLink(updatedIdeUrl, ownerToken, connectParams)
229251 if (joinLink.isNullOrEmpty()) {
252+ activeConnections.remove(connectionKeyId)
230253 setErrorMessage(" failed to fetch JetBrains Gateway Join Link." )
231254 return @launch
232255 }
@@ -239,6 +262,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
239262 clientHandle.clientClosed.advise(connectionLifetime) {
240263 application.invokeLater {
241264 connectionLifetime.terminate()
265+ activeConnections.remove(connectionKeyId)
242266 }
243267 }
244268 clientHandle.onClientPresenceChanged.advise(connectionLifetime) {
0 commit comments