4
4
5
5
package io.gitpod.jetbrains.remote.latest
6
6
7
+ import com.intellij.openapi.Disposable
7
8
import com.intellij.openapi.client.ClientProjectSession
8
9
import com.intellij.openapi.diagnostic.thisLogger
9
- import com.intellij.openapi.rd.createLifetime
10
10
import com.intellij.remoteDev.util.onTerminationOrNow
11
11
import com.intellij.util.application
12
- import com.jetbrains.rdserver.portForwarding.PortForwardingDiscovery
13
- import com.jetbrains.rdserver.portForwarding.PortForwardingManager
14
- import com.jetbrains.rdserver.portForwarding.remoteDev.PortEventsProcessor
12
+ import com.jetbrains.rd.util.lifetime.Lifetime
15
13
import com.jetbrains.rdserver.terminal.BackendTerminalManager
16
14
import io.gitpod.jetbrains.remote.GitpodManager
17
15
import io.gitpod.supervisor.api.Status
@@ -27,33 +25,43 @@ import java.util.concurrent.CompletableFuture
27
25
import java.util.concurrent.TimeUnit
28
26
29
27
@Suppress(" UnstableApiUsage" )
30
- class GitpodTerminalService (private val session : ClientProjectSession ) {
28
+ class GitpodTerminalService (session : ClientProjectSession ) : Disposable {
31
29
private companion object {
32
- var hasStarted = false
33
- val forwardedPortsList : MutableSet < Int > = mutableSetOf ()
30
+ /* * Indicates if this service is already running, because we shouldn't run it more than once. */
31
+ var isRunning = false
34
32
}
35
33
34
+ private val lifetime = Lifetime .Eternal .createNested()
36
35
private val terminalView = TerminalView .getInstance(session.project)
37
36
private val backendTerminalManager = BackendTerminalManager .getInstance(session.project)
38
- private val portForwardingManager = PortForwardingManager .getInstance(session.project)
39
37
private val terminalServiceFutureStub = TerminalServiceGrpc .newFutureStub(GitpodManager .supervisorChannel)
40
38
private val statusServiceStub = StatusServiceGrpc .newStub(GitpodManager .supervisorChannel)
41
39
42
- init { start() }
40
+ override fun dispose () {
41
+ lifetime.terminate()
42
+ }
43
+
44
+ init {
45
+ run ()
46
+ }
43
47
44
- private fun start () {
45
- if (application.isHeadlessEnvironment || hasStarted ) return
48
+ private fun run () {
49
+ if (application.isHeadlessEnvironment || isRunning ) return
46
50
47
- hasStarted = true
51
+ isRunning = true
48
52
49
- application.executeOnPooledThread {
53
+ val task = application.executeOnPooledThread {
50
54
val terminals = getSupervisorTerminalsList()
51
55
val tasks = getSupervisorTasksList()
52
56
53
57
application.invokeLater {
54
58
createTerminalsAttachedToTasks(terminals, tasks)
55
59
}
56
60
}
61
+
62
+ lifetime.onTerminationOrNow {
63
+ task.cancel(true )
64
+ }
57
65
}
58
66
59
67
private fun createSharedTerminalAndExecuteCommand (title : String , command : String ) {
@@ -62,11 +70,12 @@ class GitpodTerminalService(private val session: ClientProjectSession) {
62
70
backendTerminalManager.createNewSharedTerminal(UUID .randomUUID().toString(), title)
63
71
64
72
for (widget in terminalView.widgets) {
65
- if (registeredTerminals.contains(widget)) continue
66
-
67
- widget.terminalTitle.change { applicationTitle = title }
68
-
69
- (widget as ShellTerminalWidget ).executeCommand(command)
73
+ if (! registeredTerminals.contains(widget)) {
74
+ widget.terminalTitle.change {
75
+ applicationTitle = title
76
+ }
77
+ (widget as ShellTerminalWidget ).executeCommand(command)
78
+ }
70
79
}
71
80
}
72
81
@@ -85,10 +94,11 @@ class GitpodTerminalService(private val session: ClientProjectSession) {
85
94
86
95
for (task in tasks) {
87
96
val terminalAlias = task.terminal
88
- val terminal = aliasToTerminalMap[terminalAlias] ? : continue
97
+ val terminal = aliasToTerminalMap[terminalAlias]
89
98
90
- createAttachedSharedTerminal(terminal)
91
- autoForwardAllPortsFromTerminal(terminal)
99
+ if (terminal != null ) {
100
+ createAttachedSharedTerminal(terminal)
101
+ }
92
102
}
93
103
}
94
104
@@ -102,17 +112,22 @@ class GitpodTerminalService(private val session: ClientProjectSession) {
102
112
103
113
val taskStatusResponseObserver = object :
104
114
ClientResponseObserver <Status .TasksStatusRequest , Status .TasksStatusResponse > {
105
- override fun beforeStart (request : ClientCallStreamObserver <Status .TasksStatusRequest >) = Unit
115
+ override fun beforeStart (request : ClientCallStreamObserver <Status .TasksStatusRequest >) {
116
+ lifetime.onTerminationOrNow {
117
+ request.cancel(null , null )
118
+ }
119
+ }
106
120
107
121
override fun onNext (response : Status .TasksStatusResponse ) {
108
122
for (task in response.tasksList) {
109
- if (task.state == = Status .TaskState .opening) return
123
+ if (task.state == = Status .TaskState .opening) {
124
+ return
125
+ }
110
126
}
111
-
112
127
completableFuture.complete(response.tasksList)
113
128
}
114
129
115
- override fun onCompleted () = Unit
130
+ override fun onCompleted () {}
116
131
117
132
override fun onError (throwable : Throwable ) {
118
133
completableFuture.completeExceptionally(throwable)
@@ -128,7 +143,7 @@ class GitpodTerminalService(private val session: ClientProjectSession) {
128
143
}
129
144
130
145
thisLogger().error(
131
- " gitpod: Got an error while trying to get tasks list from Supervisor. Trying again in on second." ,
146
+ " Got an error while trying to get tasks list from Supervisor. Trying again in on second." ,
132
147
throwable
133
148
)
134
149
}
@@ -149,6 +164,10 @@ class GitpodTerminalService(private val session: ClientProjectSession) {
149
164
150
165
val listTerminalsResponseFuture = terminalServiceFutureStub.list(listTerminalsRequest)
151
166
167
+ lifetime.onTerminationOrNow {
168
+ listTerminalsResponseFuture.cancel(true )
169
+ }
170
+
152
171
val listTerminalsResponse = listTerminalsResponseFuture.get()
153
172
154
173
terminalsList = listTerminalsResponse.terminalsList
@@ -158,7 +177,7 @@ class GitpodTerminalService(private val session: ClientProjectSession) {
158
177
}
159
178
160
179
thisLogger().error(
161
- " gitpod: Got an error while trying to get terminals list from Supervisor. Trying again in on second." ,
180
+ " Got an error while trying to get terminals list from Supervisor. Trying again in on second." ,
162
181
throwable
163
182
)
164
183
}
@@ -177,40 +196,4 @@ class GitpodTerminalService(private val session: ClientProjectSession) {
177
196
" gp tasks attach ${supervisorTerminal.alias} "
178
197
)
179
198
}
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
- }
216
199
}
0 commit comments