4
4
5
5
package io.gitpod.jetbrains.remote
6
6
7
+ import com.intellij.openapi.Disposable
7
8
import com.intellij.openapi.diagnostic.thisLogger
8
9
import com.intellij.openapi.project.Project
10
+ import com.intellij.openapi.rd.defineNestedLifetime
11
+ import com.intellij.remoteDev.util.onTerminationOrNow
9
12
import com.intellij.util.application
10
13
import com.jediterm.terminal.ui.TerminalWidget
11
14
import com.jediterm.terminal.ui.TerminalWidgetListener
15
+ import com.jetbrains.rd.framework.util.launch
12
16
import com.jetbrains.rdserver.terminal.BackendTerminalManager
13
17
import io.gitpod.supervisor.api.Status
14
18
import io.gitpod.supervisor.api.StatusServiceGrpc
@@ -17,18 +21,18 @@ import io.gitpod.supervisor.api.TerminalServiceGrpc
17
21
import io.grpc.StatusRuntimeException
18
22
import io.grpc.stub.ClientCallStreamObserver
19
23
import io.grpc.stub.ClientResponseObserver
24
+ import kotlinx.coroutines.delay
25
+ import kotlinx.coroutines.future.await
26
+ import kotlinx.coroutines.guava.await
20
27
import org.jetbrains.plugins.terminal.ShellTerminalWidget
21
28
import org.jetbrains.plugins.terminal.TerminalView
22
29
import java.util.*
23
30
import java.util.concurrent.CompletableFuture
24
31
import java.util.concurrent.ExecutionException
25
- import java.util.concurrent.TimeUnit
26
-
27
- class GitpodTerminalService (project : Project ) {
28
- private companion object {
29
- var hasStarted = false
30
- }
31
32
33
+ @Suppress(" UnstableApiUsage" )
34
+ class GitpodTerminalService (project : Project ): Disposable {
35
+ private val lifetime = defineNestedLifetime()
32
36
private val terminalView = TerminalView .getInstance(project)
33
37
private val backendTerminalManager = BackendTerminalManager .getInstance(project)
34
38
private val terminalServiceFutureStub = TerminalServiceGrpc .newFutureStub(GitpodManager .supervisorChannel)
@@ -39,12 +43,12 @@ class GitpodTerminalService(project: Project) {
39
43
start()
40
44
}
41
45
42
- private fun start () {
43
- if (application.isHeadlessEnvironment || hasStarted) return
46
+ override fun dispose () = Unit
44
47
45
- hasStarted = true
48
+ private fun start () {
49
+ if (application.isHeadlessEnvironment) return
46
50
47
- application.executeOnPooledThread {
51
+ lifetime.launch {
48
52
val terminals = getSupervisorTerminalsList()
49
53
val tasks = getSupervisorTasksList()
50
54
@@ -95,7 +99,7 @@ class GitpodTerminalService(project: Project) {
95
99
}
96
100
}
97
101
98
- private tailrec fun getSupervisorTasksList (): List <Status .TaskStatus > {
102
+ private tailrec suspend fun getSupervisorTasksList (): List <Status .TaskStatus > {
99
103
var tasksList: List <Status .TaskStatus >? = null
100
104
101
105
try {
@@ -124,7 +128,7 @@ class GitpodTerminalService(project: Project) {
124
128
125
129
statusServiceStub.tasksStatus(taskStatusRequest, taskStatusResponseObserver)
126
130
127
- tasksList = completableFuture.get ()
131
+ tasksList = completableFuture.await ()
128
132
} catch (throwable: Throwable ) {
129
133
if (throwable is InterruptedException ) {
130
134
throw throwable
@@ -140,20 +144,20 @@ class GitpodTerminalService(project: Project) {
140
144
return if (tasksList != null ) {
141
145
tasksList
142
146
} else {
143
- TimeUnit . SECONDS .sleep( 1 )
147
+ delay( 1000 )
144
148
getSupervisorTasksList()
145
149
}
146
150
}
147
151
148
- private tailrec fun getSupervisorTerminalsList (): List <TerminalOuterClass .Terminal > {
152
+ private tailrec suspend fun getSupervisorTerminalsList (): List <TerminalOuterClass .Terminal > {
149
153
var terminalsList: List <TerminalOuterClass .Terminal >? = null
150
154
151
155
try {
152
156
val listTerminalsRequest = TerminalOuterClass .ListTerminalsRequest .newBuilder().build()
153
157
154
158
val listTerminalsResponseFuture = terminalServiceFutureStub.list(listTerminalsRequest)
155
159
156
- val listTerminalsResponse = listTerminalsResponseFuture.get ()
160
+ val listTerminalsResponse = listTerminalsResponseFuture.await ()
157
161
158
162
terminalsList = listTerminalsResponse.terminalsList
159
163
} catch (throwable: Throwable ) {
@@ -171,7 +175,7 @@ class GitpodTerminalService(project: Project) {
171
175
return if (terminalsList != null ) {
172
176
terminalsList
173
177
} else {
174
- TimeUnit . SECONDS .sleep( 1 )
178
+ delay( 1000 )
175
179
getSupervisorTerminalsList()
176
180
}
177
181
}
@@ -182,6 +186,8 @@ class GitpodTerminalService(project: Project) {
182
186
" gp tasks attach ${supervisorTerminal.alias} "
183
187
) ? : return
184
188
189
+ closeTerminalWidgetWhenClientGetsClosed(shellTerminalWidget)
190
+
185
191
exitTaskWhenTerminalWidgetGetsClosed(supervisorTerminal, shellTerminalWidget)
186
192
187
193
listenForTaskTerminationAndTitleChanges(supervisorTerminal, shellTerminalWidget)
@@ -190,7 +196,7 @@ class GitpodTerminalService(project: Project) {
190
196
private fun listenForTaskTerminationAndTitleChanges (
191
197
supervisorTerminal : TerminalOuterClass .Terminal ,
192
198
shellTerminalWidget : ShellTerminalWidget
193
- ) = application.executeOnPooledThread {
199
+ ) = lifetime.launch {
194
200
var hasOpenSessions = true
195
201
196
202
while (hasOpenSessions) {
@@ -241,7 +247,7 @@ class GitpodTerminalService(project: Project) {
241
247
terminalServiceStub.listen(listenTerminalRequest, listenTerminalResponseObserver)
242
248
243
249
try {
244
- completableFuture.get ()
250
+ completableFuture.await ()
245
251
} catch (throwable: Throwable ) {
246
252
if (
247
253
throwable is StatusRuntimeException ||
@@ -259,7 +265,7 @@ class GitpodTerminalService(project: Project) {
259
265
" '${supervisorTerminal.title} ' terminal. Trying again in one second." , throwable)
260
266
}
261
267
262
- TimeUnit . SECONDS .sleep( 1 )
268
+ delay( 1000 )
263
269
}
264
270
}
265
271
@@ -270,12 +276,23 @@ class GitpodTerminalService(project: Project) {
270
276
@Suppress(" ObjectLiteralToLambda" )
271
277
shellTerminalWidget.addListener(object : TerminalWidgetListener {
272
278
override fun allSessionsClosed (widget : TerminalWidget ) {
273
- terminalServiceFutureStub.shutdown(
274
- TerminalOuterClass .ShutdownTerminalRequest .newBuilder()
275
- .setAlias(supervisorTerminal.alias)
276
- .build()
277
- )
279
+ lifetime.launch {
280
+ delay(5000 )
281
+ terminalServiceFutureStub.shutdown(
282
+ TerminalOuterClass .ShutdownTerminalRequest .newBuilder()
283
+ .setAlias(supervisorTerminal.alias)
284
+ .build()
285
+ )
286
+ }
278
287
}
279
288
})
280
289
}
290
+
291
+ private fun closeTerminalWidgetWhenClientGetsClosed (
292
+ shellTerminalWidget : ShellTerminalWidget
293
+ ) {
294
+ lifetime.onTerminationOrNow {
295
+ shellTerminalWidget.close()
296
+ }
297
+ }
281
298
}
0 commit comments