Skip to content

Commit 95f02d8

Browse files
felladrinroboquat
authored andcommitted
Auto-forward Task Terminals Ports on JetBrains IDEs
1 parent 8b88f26 commit 95f02d8

File tree

1 file changed

+63
-46
lines changed

1 file changed

+63
-46
lines changed

components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/latest/GitpodTerminalService.kt

Lines changed: 63 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44

55
package io.gitpod.jetbrains.remote.latest
66

7-
import com.intellij.openapi.Disposable
87
import com.intellij.openapi.client.ClientProjectSession
98
import com.intellij.openapi.diagnostic.thisLogger
9+
import com.intellij.openapi.rd.createLifetime
1010
import com.intellij.remoteDev.util.onTerminationOrNow
1111
import com.intellij.util.application
12-
import com.jetbrains.rd.util.lifetime.Lifetime
12+
import com.jetbrains.rdserver.portForwarding.PortForwardingDiscovery
13+
import com.jetbrains.rdserver.portForwarding.PortForwardingManager
14+
import com.jetbrains.rdserver.portForwarding.remoteDev.PortEventsProcessor
1315
import com.jetbrains.rdserver.terminal.BackendTerminalManager
1416
import io.gitpod.jetbrains.remote.GitpodManager
1517
import io.gitpod.supervisor.api.Status
@@ -25,43 +27,33 @@ import java.util.concurrent.CompletableFuture
2527
import java.util.concurrent.TimeUnit
2628

2729
@Suppress("UnstableApiUsage")
28-
class GitpodTerminalService(session: ClientProjectSession) : Disposable {
30+
class GitpodTerminalService(private val session: ClientProjectSession) {
2931
private companion object {
30-
/** Indicates if this service is already running, because we shouldn't run it more than once. */
31-
var isRunning = false
32+
var hasStarted = false
33+
val forwardedPortsList: MutableSet<Int> = mutableSetOf()
3234
}
3335

34-
private val lifetime = Lifetime.Eternal.createNested()
3536
private val terminalView = TerminalView.getInstance(session.project)
3637
private val backendTerminalManager = BackendTerminalManager.getInstance(session.project)
38+
private val portForwardingManager = PortForwardingManager.getInstance(session.project)
3739
private val terminalServiceFutureStub = TerminalServiceGrpc.newFutureStub(GitpodManager.supervisorChannel)
3840
private val statusServiceStub = StatusServiceGrpc.newStub(GitpodManager.supervisorChannel)
3941

40-
override fun dispose() {
41-
lifetime.terminate()
42-
}
43-
44-
init {
45-
run()
46-
}
42+
init { start() }
4743

48-
private fun run() {
49-
if (application.isHeadlessEnvironment || isRunning) return
44+
private fun start() {
45+
if (application.isHeadlessEnvironment || hasStarted) return
5046

51-
isRunning = true
47+
hasStarted = true
5248

53-
val task = application.executeOnPooledThread {
49+
application.executeOnPooledThread {
5450
val terminals = getSupervisorTerminalsList()
5551
val tasks = getSupervisorTasksList()
5652

5753
application.invokeLater {
5854
createTerminalsAttachedToTasks(terminals, tasks)
5955
}
6056
}
61-
62-
lifetime.onTerminationOrNow {
63-
task.cancel(true)
64-
}
6557
}
6658

6759
private fun createSharedTerminalAndExecuteCommand(title: String, command: String) {
@@ -70,12 +62,11 @@ class GitpodTerminalService(session: ClientProjectSession) : Disposable {
7062
backendTerminalManager.createNewSharedTerminal(UUID.randomUUID().toString(), title)
7163

7264
for (widget in terminalView.widgets) {
73-
if (!registeredTerminals.contains(widget)) {
74-
widget.terminalTitle.change {
75-
applicationTitle = title
76-
}
77-
(widget as ShellTerminalWidget).executeCommand(command)
78-
}
65+
if (registeredTerminals.contains(widget)) continue
66+
67+
widget.terminalTitle.change { applicationTitle = title }
68+
69+
(widget as ShellTerminalWidget).executeCommand(command)
7970
}
8071
}
8172

@@ -94,11 +85,10 @@ class GitpodTerminalService(session: ClientProjectSession) : Disposable {
9485

9586
for (task in tasks) {
9687
val terminalAlias = task.terminal
97-
val terminal = aliasToTerminalMap[terminalAlias]
88+
val terminal = aliasToTerminalMap[terminalAlias] ?: continue
9889

99-
if (terminal != null) {
100-
createAttachedSharedTerminal(terminal)
101-
}
90+
createAttachedSharedTerminal(terminal)
91+
autoForwardAllPortsFromTerminal(terminal)
10292
}
10393
}
10494

@@ -112,22 +102,17 @@ class GitpodTerminalService(session: ClientProjectSession) : Disposable {
112102

113103
val taskStatusResponseObserver = object :
114104
ClientResponseObserver<Status.TasksStatusRequest, Status.TasksStatusResponse> {
115-
override fun beforeStart(request: ClientCallStreamObserver<Status.TasksStatusRequest>) {
116-
lifetime.onTerminationOrNow {
117-
request.cancel(null, null)
118-
}
119-
}
105+
override fun beforeStart(request: ClientCallStreamObserver<Status.TasksStatusRequest>) = Unit
120106

121107
override fun onNext(response: Status.TasksStatusResponse) {
122108
for (task in response.tasksList) {
123-
if (task.state === Status.TaskState.opening) {
124-
return
125-
}
109+
if (task.state === Status.TaskState.opening) return
126110
}
111+
127112
completableFuture.complete(response.tasksList)
128113
}
129114

130-
override fun onCompleted() {}
115+
override fun onCompleted() = Unit
131116

132117
override fun onError(throwable: Throwable) {
133118
completableFuture.completeExceptionally(throwable)
@@ -143,7 +128,7 @@ class GitpodTerminalService(session: ClientProjectSession) : Disposable {
143128
}
144129

145130
thisLogger().error(
146-
"Got an error while trying to get tasks list from Supervisor. Trying again in on second.",
131+
"gitpod: Got an error while trying to get tasks list from Supervisor. Trying again in on second.",
147132
throwable
148133
)
149134
}
@@ -164,10 +149,6 @@ class GitpodTerminalService(session: ClientProjectSession) : Disposable {
164149

165150
val listTerminalsResponseFuture = terminalServiceFutureStub.list(listTerminalsRequest)
166151

167-
lifetime.onTerminationOrNow {
168-
listTerminalsResponseFuture.cancel(true)
169-
}
170-
171152
val listTerminalsResponse = listTerminalsResponseFuture.get()
172153

173154
terminalsList = listTerminalsResponse.terminalsList
@@ -177,7 +158,7 @@ class GitpodTerminalService(session: ClientProjectSession) : Disposable {
177158
}
178159

179160
thisLogger().error(
180-
"Got an error while trying to get terminals list from Supervisor. Trying again in on second.",
161+
"gitpod: Got an error while trying to get terminals list from Supervisor. Trying again in on second.",
181162
throwable
182163
)
183164
}
@@ -196,4 +177,40 @@ class GitpodTerminalService(session: ClientProjectSession) : Disposable {
196177
"gp tasks attach ${supervisorTerminal.alias}"
197178
)
198179
}
180+
181+
private fun autoForwardAllPortsFromTerminal(supervisorTerminal: TerminalOuterClass.Terminal) {
182+
val projectLifetime = session.project.createLifetime()
183+
184+
val discoveryCallback = object : PortForwardingDiscovery {
185+
/**
186+
* @return Whether port should be forwarded or not.
187+
* We shouldn't try to forward ports that are already forwarded.
188+
*/
189+
override fun onPortDiscovered(hostPort: Int): Boolean = !forwardedPortsList.contains(hostPort)
190+
191+
override fun getEventsProcessor(hostPort: Int) = object : PortEventsProcessor {
192+
override fun onPortForwarded(hostPort: Int, clientPort: Int) {
193+
forwardedPortsList.add(hostPort)
194+
thisLogger().info("gitpod: Forwarded port $hostPort from Supervisor's Terminal " +
195+
"${supervisorTerminal.pid} to client's port $clientPort.")
196+
197+
projectLifetime.onTerminationOrNow {
198+
if (forwardedPortsList.contains(hostPort)) {
199+
forwardedPortsList.remove(hostPort)
200+
portForwardingManager.removePort(hostPort)
201+
thisLogger().info("gitpod: Removing forwarded port $hostPort from Supervisor's Terminal " +
202+
"${supervisorTerminal.pid}")
203+
}
204+
}
205+
}
206+
207+
override fun onPortForwardingFailed(hostPort: Int, reason: String) {
208+
thisLogger().error("gitpod: Failed to forward port $hostPort from Supervisor's Terminal " +
209+
"${supervisorTerminal.pid}: $reason")
210+
}
211+
}
212+
}
213+
214+
portForwardingManager.forwardPortsOfPid(projectLifetime, supervisorTerminal.pid, discoveryCallback, true)
215+
}
199216
}

0 commit comments

Comments
 (0)