diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt index 63b6f39892212f..962f8e1e5f97cd 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt @@ -15,6 +15,8 @@ import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.project.Project import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream import com.intellij.openapi.util.io.FileUtilRt +import com.intellij.openapi.wm.IdeFocusManager +import com.intellij.ui.AppIcon import com.intellij.util.application import com.intellij.util.withFragment import com.intellij.util.withPath @@ -65,6 +67,11 @@ class GitpodCLIService : RestService() { val file = parseFilePath(fileStr) ?: return "invalid file" val shouldWait = getBooleanParameter("wait", urlDecoder) return withClient(request, context) { + val toFocus = IdeFocusManager.getGlobalInstance()?.lastFocusedFrame + thisLogger().warn("toFocus = $toFocus") + if (toFocus != null) { + AppIcon.getInstance().requestFocus(toFocus) + } CommandLineProcessor.doOpenFileOrProject(file, shouldWait).future.get() } } diff --git a/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt b/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt index e72304ee89426b..f20088cd9941f0 100644 --- a/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt +++ b/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt @@ -12,6 +12,7 @@ import com.intellij.ide.BrowserUtil import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.ui.Messages import com.intellij.remote.RemoteCredentialsHolder import com.intellij.ssh.AskAboutHostKey import com.intellij.ssh.OpenSshLikeHostKeyVerifier @@ -31,6 +32,7 @@ import com.jetbrains.gateway.ssh.ClientOverSshTunnelConnector import com.jetbrains.gateway.ssh.SshHostTunnelConnector import com.jetbrains.gateway.thinClientLink.ThinClientHandle import com.jetbrains.rd.util.URI +import com.jetbrains.rd.util.concurrentMapOf import com.jetbrains.rd.util.lifetime.Lifetime import io.gitpod.gitpodprotocol.api.entities.WorkspaceInstance import io.gitpod.jetbrains.icons.GitpodIcons @@ -49,7 +51,7 @@ import kotlin.coroutines.coroutineContext @Suppress("UnstableApiUsage", "OPT_IN_USAGE") class GitpodConnectionProvider : GatewayConnectionProvider { - + private val activeConnections = concurrentMapOf() private val gitpod = service() private val httpClient = HttpClient.newBuilder() @@ -59,6 +61,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider { private val jacksonMapper = jacksonObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + override suspend fun connect( parameters: Map, requestor: ConnectionRequestor @@ -74,6 +77,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider { parameters["workspaceId"]!!, parameters["backendPort"] ) + val client = gitpod.obtainClient(connectParams.gitpodHost) val connectionLifetime = Lifetime.Eternal.createNested() val updates = client.listenToWorkspace(connectionLifetime, connectParams.workspaceId) @@ -144,6 +148,22 @@ class GitpodConnectionProvider : GatewayConnectionProvider { connectionPanel.repaint() } + val connectionKeyId = "${connectParams.gitpodHost}-${connectParams.workspaceId}-${connectParams.backendPort}" + + if (activeConnections.containsKey(connectionKeyId)) { + val message = "You are trying to connect to a workspace that has a session already open" + val title = "Oops" + val okButton = Messages.getOkButton() + val options = arrayOf(okButton) + val defaultIndex = 0 + val icon = Messages.getWarningIcon() + Messages.showDialog(message, title, options, defaultIndex, icon) + + val errMessage = "A connection to the same workspace already exists: $connectionKeyId" + thisLogger().warn(errMessage) + throw IllegalStateException(errMessage) + } + GlobalScope.launch { var thinClient: ThinClientHandle? = null var thinClientJob: Job? = null @@ -230,6 +250,10 @@ class GitpodConnectionProvider : GatewayConnectionProvider { setErrorMessage("failed to fetch JetBrains Gateway Join Link.") return@launch } + + // TODO: is this the right place? + activeConnections[connectionKeyId] = true + val connector = ClientOverSshTunnelConnector( connectionLifetime, SshHostTunnelConnector(credentials), @@ -239,6 +263,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider { clientHandle.clientClosed.advise(connectionLifetime) { application.invokeLater { connectionLifetime.terminate() + activeConnections.remove(connectionKeyId) } } clientHandle.onClientPresenceChanged.advise(connectionLifetime) {