@@ -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
@@ -31,6 +32,7 @@ import com.jetbrains.gateway.ssh.ClientOverSshTunnelConnector
3132import com.jetbrains.gateway.ssh.SshHostTunnelConnector
3233import com.jetbrains.gateway.thinClientLink.ThinClientHandle
3334import com.jetbrains.rd.util.URI
35+ import com.jetbrains.rd.util.concurrentMapOf
3436import com.jetbrains.rd.util.lifetime.Lifetime
3537import io.gitpod.gitpodprotocol.api.entities.WorkspaceInstance
3638import io.gitpod.jetbrains.icons.GitpodIcons
@@ -49,7 +51,7 @@ import kotlin.coroutines.coroutineContext
4951
5052@Suppress(" UnstableApiUsage" , " OPT_IN_USAGE" )
5153class GitpodConnectionProvider : GatewayConnectionProvider {
52-
54+ private val activeConnections = concurrentMapOf< String , Boolean >()
5355 private val gitpod = service<GitpodConnectionService >()
5456
5557 private val httpClient = HttpClient .newBuilder()
@@ -59,6 +61,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
5961 private val jacksonMapper = jacksonObjectMapper()
6062 .configure(DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false )
6163
64+
6265 override suspend fun connect (
6366 parameters : Map <String , String >,
6467 requestor : ConnectionRequestor
@@ -74,6 +77,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
7477 parameters[" workspaceId" ]!! ,
7578 parameters[" backendPort" ]
7679 )
80+
7781 val client = gitpod.obtainClient(connectParams.gitpodHost)
7882 val connectionLifetime = Lifetime .Eternal .createNested()
7983 val updates = client.listenToWorkspace(connectionLifetime, connectParams.workspaceId)
@@ -144,6 +148,22 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
144148 connectionPanel.repaint()
145149 }
146150
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 IllegalArgumentException (errMessage)
165+ }
166+
147167 GlobalScope .launch {
148168 var thinClient: ThinClientHandle ? = null
149169 var thinClientJob: Job ? = null
@@ -230,6 +250,12 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
230250 setErrorMessage(" failed to fetch JetBrains Gateway Join Link." )
231251 return @launch
232252 }
253+
254+ // TODO: is this the right place?
255+ activeConnections[connectionKeyId] = true
256+
257+ thisLogger().warn(" Storing connection for $connectionKeyId " )
258+
233259 val connector = ClientOverSshTunnelConnector (
234260 connectionLifetime,
235261 SshHostTunnelConnector (credentials),
@@ -239,6 +265,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
239265 clientHandle.clientClosed.advise(connectionLifetime) {
240266 application.invokeLater {
241267 connectionLifetime.terminate()
268+ activeConnections.remove(connectionKeyId)
242269 }
243270 }
244271 clientHandle.onClientPresenceChanged.advise(connectionLifetime) {
0 commit comments