Skip to content

[jb]: customize remote indicator #8371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pluginUntilBuild=213.*
pluginVerifierIdeVersions=2021.3.1
# IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties
platformType=IU
platformVersion=213-EAP-SNAPSHOT
platformVersion=213.6777.52
platformDownloadSources=true
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
# Licensed under the GNU Affero General Public License (AGPL).
# See License-AGPL.txt in the project root for license information.

set -e
set -o pipefail

TEST_BACKEND_DIR=/workspace/ide-backend
if [ ! -d "$TEST_BACKEND_DIR" ]; then
mkdir -p $TEST_BACKEND_DIR
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.

package io.gitpod.jetbrains.remote

import com.intellij.openapi.components.service
import com.intellij.remoteDev.customization.GatewayBranding
import io.gitpod.jetbrains.remote.icons.GitpodIcons
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.future.await
import kotlinx.coroutines.launch
import javax.swing.Icon

class GitpodBranding : GatewayBranding {

val manager = service<GitpodManager>()

/*
TODO(ak) GITPOD_WORSPACE_ID is a subject to change
ideally we should not rely on it, but here `getName` is sync
alternatively we could precompute another env var based on supervisor info endpoint
before starting backend
*/
private var name = System.getenv("GITPOD_WORKSPACE_ID") ?: "Gitpod"
init {
GlobalScope.launch {
val info = manager.pendingInfo.await()
name = info.workspaceId
}
}

override fun getIcon(): Icon {
return GitpodIcons.Logo
}

override fun getName(): String {
return name
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class GitpodClientProjectSessionTracker(
event = "jb_session"
properties = mapOf(
"sessionId" to session.clientId.value,
"instanceId" to info.infoResponse.instanceId,
"workspaceId" to info.infoResponse.workspaceId,
"instanceId" to info.instanceId,
"workspaceId" to info.workspaceId,
"appName" to ApplicationInfo.getInstance().versionName,
"appVersion" to ApplicationInfo.getInstance().fullVersion,
"timestamp" to System.currentTimeMillis()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ import git4idea.config.GitVcsApplicationSettings
import io.gitpod.gitpodprotocol.api.GitpodClient
import io.gitpod.gitpodprotocol.api.GitpodServerLauncher
import io.gitpod.jetbrains.remote.services.HeartbeatService
import io.gitpod.jetbrains.remote.services.SupervisorInfoService
import io.gitpod.supervisor.api.*
import io.gitpod.supervisor.api.Info.WorkspaceInfoResponse
import io.gitpod.supervisor.api.Notification.*
import io.gitpod.supervisor.api.NotificationServiceGrpc
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
import io.grpc.stub.ClientCallStreamObserver
import io.grpc.stub.ClientResponseObserver
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.future.await
import kotlinx.coroutines.guava.asDeferred
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.jetbrains.ide.BuiltInServerManager
Expand All @@ -37,10 +40,16 @@ import java.time.Duration
import java.util.concurrent.CancellationException
import java.util.concurrent.CompletableFuture
import javax.websocket.DeploymentException
import io.gitpod.jetbrains.remote.utils.Retrier.retry

@Service
class GitpodManager : Disposable {

companion object {
// there should be only one channel per an application to avoid memory leak
val supervisorChannel: ManagedChannel = ManagedChannelBuilder.forTarget("localhost:22999").usePlaintext().build()
}

val devMode = System.getenv("JB_DEV").toBoolean()

private val lifetime = Lifetime.Eternal.createNested()
Expand Down Expand Up @@ -84,8 +93,8 @@ class GitpodManager : Disposable {

private val notificationGroup = NotificationGroupManager.getInstance().getNotificationGroup("Gitpod Notifications")
private val notificationsJob = GlobalScope.launch {
val notifications = NotificationServiceGrpc.newStub(SupervisorInfoService.channel)
val futureNotifications = NotificationServiceGrpc.newFutureStub(SupervisorInfoService.channel)
val notifications = NotificationServiceGrpc.newStub(supervisorChannel)
val futureNotifications = NotificationServiceGrpc.newFutureStub(supervisorChannel)
while (isActive) {
try {
val f = CompletableFuture<Void>()
Expand Down Expand Up @@ -145,11 +154,18 @@ class GitpodManager : Disposable {
}
}

val pendingInfo = CompletableFuture<SupervisorInfoService.Result>()
val pendingInfo = CompletableFuture<WorkspaceInfoResponse>()
private val infoJob = GlobalScope.launch {
try {
// TOO(ak) inline SupervisorInfoService
pendingInfo.complete(SupervisorInfoService.fetch())
// TODO(ak) replace retry with proper handling of grpc errors
val infoResponse = retry(3) {
InfoServiceGrpc
.newFutureStub(supervisorChannel)
.workspaceInfo(Info.WorkspaceInfoRequest.newBuilder().build())
.asDeferred()
.await()
}
pendingInfo.complete(infoResponse)
} catch (t: Throwable) {
pendingInfo.completeExceptionally(t)
}
Expand All @@ -163,6 +179,23 @@ class GitpodManager : Disposable {
val client = GitpodClient()
private val serverJob = GlobalScope.launch {
val info = pendingInfo.await()

// TODO(ak) replace retry with proper handling of grpc errors
val tokenResponse = retry(3) {
val request = Token.GetTokenRequest.newBuilder()
.setHost(info.gitpodApi.host)
.addScope("function:sendHeartBeat")
.addScope("function:trackEvent")
.setKind("gitpod")
.build()

TokenServiceGrpc
.newFutureStub(supervisorChannel)
.getToken(request)
.asDeferred()
.await()
}

val launcher = GitpodServerLauncher.create(client)
val plugin = PluginManagerCore.getPlugin(PluginId.getId("io.gitpod.jetbrains.remote"))!!
val connect = {
Expand All @@ -171,11 +204,11 @@ class GitpodManager : Disposable {
// see https://intellij-support.jetbrains.com/hc/en-us/community/posts/360003146180/comments/360000376240
Thread.currentThread().contextClassLoader = HeartbeatService::class.java.classLoader
launcher.listen(
info.infoResponse.gitpodApi.endpoint,
info.infoResponse.gitpodHost,
info.gitpodApi.endpoint,
info.gitpodHost,
plugin.pluginId.idString,
plugin.version,
info.tokenResponse.token
tokenResponse.token
)
} finally {
Thread.currentThread().contextClassLoader = originalClassLoader;
Expand All @@ -186,7 +219,7 @@ class GitpodManager : Disposable {
val maxReconnectionDelay = 30 * 1000L
val reconnectionDelayGrowFactor = 1.5;
var reconnectionDelay = minReconnectionDelay;
val gitpodHost = info.infoResponse.gitpodApi.host
val gitpodHost = info.gitpodApi.host
var closeReason: Any = "cancelled"
try {
while (kotlin.coroutines.coroutineContext.isActive) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.
package io.gitpod.jetbrains.remote.icons

import com.intellij.openapi.util.IconLoader

object GitpodIcons {
@JvmField
val Logo = IconLoader.getIcon("/icons/logo.svg", javaClass)
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class HeartbeatService : Disposable {
}

if (wasClosed != null) {
manager.client.server.sendHeartBeat(SendHeartBeatOptions(info.infoResponse.instanceId, wasClosed)).await()
manager.client.server.sendHeartBeat(SendHeartBeatOptions(info.instanceId, wasClosed)).await()
}
} catch (t: Throwable) {
thisLogger().error("gitpod: failed to check activity:", t)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
<notificationGroup id="Gitpod Notifications" displayType="BALLOON" isLogByDefault="false" />
<httpRequestHandler implementation="io.gitpod.jetbrains.remote.GitpodCLIService"/>
<projectService serviceImplementation="io.gitpod.jetbrains.remote.GitpodClientProjectSessionTracker" client="guest" preload="true"/>
<applicationService serviceImplementation="io.gitpod.jetbrains.remote.GitpodBranding"
serviceInterface="com.intellij.remoteDev.customization.GatewayBranding"
overrides="true" />
</extensions>

</idea-plugin>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.