Skip to content

Commit 8f4543d

Browse files
committed
Use CompletableFuture instead of Callbacks
1 parent 5e3ac7e commit 8f4543d

File tree

2 files changed

+69
-74
lines changed

2 files changed

+69
-74
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package io.gitpod.jetbrains.remote
66

77
import com.intellij.openapi.application.runInEdt
88
import com.intellij.openapi.client.ClientProjectSession
9-
import com.jetbrains.rdserver.terminal.BackendTerminalManager
109
import org.jetbrains.plugins.terminal.TerminalView
1110

1211
@Suppress("UnstableApiUsage")

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

Lines changed: 69 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
package io.gitpod.jetbrains.remote
66

77
import com.google.protobuf.ByteString
8+
import com.intellij.openapi.Disposable
89
import com.intellij.openapi.application.runInEdt
910
import com.intellij.openapi.diagnostic.thisLogger
1011
import com.intellij.openapi.project.Project
1112
import com.intellij.openapi.util.Key
1213
import com.intellij.openapi.wm.ToolWindowManager
1314
import com.intellij.openapi.wm.ex.ToolWindowManagerListener
1415
import com.jediterm.terminal.TtyConnector
16+
import com.jetbrains.rd.util.lifetime.Lifetime
1517
import com.jetbrains.rdserver.terminal.BackendTerminalManager
1618
import com.jetbrains.rdserver.terminal.BackendTtyConnector
1719
import io.gitpod.supervisor.api.Status.*
@@ -20,73 +22,83 @@ import io.gitpod.supervisor.api.TerminalOuterClass
2022
import io.gitpod.supervisor.api.TerminalServiceGrpc
2123
import io.grpc.StatusRuntimeException
2224
import io.grpc.stub.StreamObserver
25+
import java.io.ByteArrayOutputStream
26+
import java.io.PipedInputStream
27+
import java.io.PipedOutputStream
28+
import java.util.concurrent.CompletableFuture
2329
import kotlinx.coroutines.*
30+
import kotlinx.coroutines.future.await
31+
import kotlinx.coroutines.guava.asDeferred
2432
import org.jetbrains.plugins.terminal.ShellTerminalWidget
2533
import org.jetbrains.plugins.terminal.TerminalTabState
2634
import org.jetbrains.plugins.terminal.TerminalToolWindowFactory
2735
import org.jetbrains.plugins.terminal.TerminalView
2836
import org.jetbrains.plugins.terminal.cloud.CloudTerminalProcess
2937
import org.jetbrains.plugins.terminal.cloud.CloudTerminalRunner
30-
import java.io.ByteArrayOutputStream
31-
import java.io.PipedInputStream
32-
import java.io.PipedOutputStream
3338

34-
@Suppress("UnstableApiUsage")
35-
class GitpodTerminalService(private val project: Project) {
39+
@Suppress("UnstableApiUsage", "EXPERIMENTAL_IS_NOT_ENABLED")
40+
@OptIn(DelicateCoroutinesApi::class)
41+
class GitpodTerminalService(private val project: Project) : Disposable {
3642
companion object {
3743
val TITLE_KEY = Key.create<String>("TITLE_KEY")
3844
}
3945

46+
private val lifetime = Lifetime.Eternal.createNested()
4047
private val terminalView = TerminalView.getInstance(project)
4148
private val terminalServiceStub = TerminalServiceGrpc.newStub(GitpodManager.supervisorChannel)
49+
private val terminalServiceFutureStub =
50+
TerminalServiceGrpc.newFutureStub(GitpodManager.supervisorChannel)
4251
private val statusServiceStub = StatusServiceGrpc.newStub(GitpodManager.supervisorChannel)
4352
private val backendTerminalManager = BackendTerminalManager.getInstance(project)
4453

54+
override fun dispose() {
55+
lifetime.terminate()
56+
}
57+
4558
init {
46-
afterTerminalToolWindowGetsRegistered {
47-
withSupervisorTasksList { tasksList ->
48-
withSupervisorTerminalsList { terminalsList ->
49-
runInEdt {
50-
for (terminalWidget in terminalView.widgets) {
51-
val terminalContent = terminalView.toolWindow.contentManager.getContent(terminalWidget)
52-
val terminalTitle = terminalContent.getUserData(TITLE_KEY)
53-
if (terminalTitle != null) {
54-
debug("Closing terminal $terminalTitle before opening it again.")
55-
terminalWidget.close()
56-
}
57-
}
59+
GlobalScope.launch {
60+
getTerminalToolWindowRegisteredEvent().await()
61+
val tasksList = getSupervisorTasksList().await()
62+
val terminalsList = getSupervisorTerminalsList().await().terminalsList
63+
debug("Got a list of Supervisor terminals: ${terminalsList}")
64+
runInEdt {
65+
for (terminalWidget in terminalView.widgets) {
66+
val terminalContent =
67+
terminalView.toolWindow.contentManager.getContent(terminalWidget)
68+
val terminalTitle = terminalContent.getUserData(TITLE_KEY)
69+
if (terminalTitle != null) {
70+
debug("Closing terminal $terminalTitle before opening it again.")
71+
terminalWidget.close()
72+
}
73+
}
5874

59-
if (tasksList.isEmpty() || terminalsList.isEmpty()) {
60-
backendTerminalManager.createNewSharedTerminal(
61-
"GitpodTerminal",
62-
"Terminal"
63-
)
64-
} else {
65-
val aliasToTerminalMap:
66-
MutableMap<String, TerminalOuterClass.Terminal> =
67-
mutableMapOf()
68-
69-
for (terminal in terminalsList) {
70-
val terminalAlias = terminal.alias
71-
aliasToTerminalMap[terminalAlias] = terminal
72-
}
75+
if (tasksList.isEmpty() || terminalsList.isEmpty()) {
76+
backendTerminalManager.createNewSharedTerminal("GitpodTerminal", "Terminal")
77+
} else {
78+
val aliasToTerminalMap: MutableMap<String, TerminalOuterClass.Terminal> =
79+
mutableMapOf()
7380

74-
for (task in tasksList) {
75-
val terminalAlias = task.terminal
76-
val terminal = aliasToTerminalMap[terminalAlias]
81+
for (terminal in terminalsList) {
82+
val terminalAlias = terminal.alias
83+
aliasToTerminalMap[terminalAlias] = terminal
84+
}
7785

78-
if (terminal != null) {
79-
createSharedTerminal(terminal)
80-
}
81-
}
86+
for (task in tasksList) {
87+
val terminalAlias = task.terminal
88+
val terminal = aliasToTerminalMap[terminalAlias]
89+
90+
if (terminal != null) {
91+
createSharedTerminal(terminal)
8292
}
8393
}
8494
}
8595
}
8696
}
8797
}
8898

89-
private fun afterTerminalToolWindowGetsRegistered(action: () -> Unit) {
99+
private fun getTerminalToolWindowRegisteredEvent(): CompletableFuture<Void> {
100+
val completableFuture = CompletableFuture<Void>()
101+
90102
debug("Waiting for TerminalToolWindow to be registered...")
91103
val toolWindowManagerListener =
92104
object : ToolWindowManagerListener {
@@ -96,19 +108,21 @@ class GitpodTerminalService(private val project: Project) {
96108
) {
97109
if (ids.contains(TerminalToolWindowFactory.TOOL_WINDOW_ID)) {
98110
debug("TerminalToolWindow got registered!")
99-
action()
111+
completableFuture.complete(null)
100112
}
101113
}
102114
}
103115

104116
project.messageBus
105117
.connect()
106118
.subscribe(ToolWindowManagerListener.TOPIC, toolWindowManagerListener)
119+
120+
return completableFuture
107121
}
108122

109-
private fun withSupervisorTasksList(action: (tasksList: List<TaskStatus>) -> Unit) {
123+
private fun getSupervisorTasksList(): CompletableFuture<List<TaskStatus>> {
124+
val completableFuture = CompletableFuture<List<TaskStatus>>()
110125
val taskStatusRequest = TasksStatusRequest.newBuilder().setObserve(true).build()
111-
112126
val taskStatusResponseObserver =
113127
object : StreamObserver<TasksStatusResponse> {
114128
override fun onNext(response: TasksStatusResponse) {
@@ -124,7 +138,7 @@ class GitpodTerminalService(private val project: Project) {
124138

125139
if (hasOpenedAllTasks) {
126140
this.onCompleted()
127-
action(response.tasksList)
141+
completableFuture.complete(response.tasksList)
128142
}
129143
}
130144

@@ -138,38 +152,18 @@ class GitpodTerminalService(private val project: Project) {
138152
"Got an error while trying to fetch tasks from Supervisor.",
139153
throwable
140154
)
155+
completableFuture.completeExceptionally(throwable)
141156
}
142157
}
143158

144159
statusServiceStub.tasksStatus(taskStatusRequest, taskStatusResponseObserver)
160+
161+
return completableFuture
145162
}
146163

147-
private fun withSupervisorTerminalsList(
148-
action: (terminalsList: List<TerminalOuterClass.Terminal>) -> Unit
149-
) {
164+
private fun getSupervisorTerminalsList(): Deferred<TerminalOuterClass.ListTerminalsResponse> {
150165
val listTerminalsRequest = TerminalOuterClass.ListTerminalsRequest.newBuilder().build()
151-
152-
val listTerminalsResponseObserver =
153-
object : StreamObserver<TerminalOuterClass.ListTerminalsResponse> {
154-
override fun onNext(response: TerminalOuterClass.ListTerminalsResponse) {
155-
debug("Got a list of Supervisor terminals: ${response.terminalsList}")
156-
action(response.terminalsList)
157-
}
158-
159-
override fun onError(throwable: Throwable) {
160-
thisLogger()
161-
.error(
162-
"Got an error while getting the list of Supervisor terminals.",
163-
throwable
164-
)
165-
}
166-
167-
override fun onCompleted() {
168-
debug("Successfully got the list of Supervisor terminals.")
169-
}
170-
}
171-
172-
terminalServiceStub.list(listTerminalsRequest, listTerminalsResponseObserver)
166+
return terminalServiceFutureStub.list(listTerminalsRequest).asDeferred()
173167
}
174168

175169
private fun createSharedTerminal(supervisorTerminal: TerminalOuterClass.Terminal) {
@@ -196,8 +190,9 @@ class GitpodTerminalService(private val project: Project) {
196190
val shellTerminalWidget =
197191
terminalView.widgets.find { widget ->
198192
terminalView.toolWindow.contentManager.getContent(widget).tabName ==
199-
terminalRunnerId
200-
} as ShellTerminalWidget
193+
terminalRunnerId
194+
} as
195+
ShellTerminalWidget
201196

202197
backendTerminalManager.shareTerminal(shellTerminalWidget, terminalRunnerId)
203198

@@ -232,7 +227,10 @@ class GitpodTerminalService(private val project: Project) {
232227
when {
233228
response.hasTitle() -> {
234229
debug("Received terminal title: ${response.title}")
235-
val terminalContent = terminalView.toolWindow.contentManager.getContent(shellTerminalWidget)
230+
val terminalContent =
231+
terminalView.toolWindow.contentManager.getContent(
232+
shellTerminalWidget
233+
)
236234
terminalContent.putUserData(TITLE_KEY, response.title)
237235
}
238236
response.hasData() -> {
@@ -299,8 +297,6 @@ class GitpodTerminalService(private val project: Project) {
299297
TerminalOuterClass.WriteTerminalRequest.newBuilder()
300298
.setAlias(supervisorTerminal.alias)
301299

302-
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
303-
@OptIn(DelicateCoroutinesApi::class)
304300
val watchTerminalInputJob =
305301
GlobalScope.launch {
306302
withContext(Dispatchers.IO) {

0 commit comments

Comments
 (0)