4
4
5
5
package io.gitpod.jetbrains.remote.latest
6
6
7
+ import com.intellij.openapi.Disposable
8
+ import com.intellij.openapi.client.ClientProjectSession
7
9
import com.intellij.openapi.components.service
8
10
import com.intellij.openapi.diagnostic.thisLogger
9
- import com.intellij.openapi.project.Project
11
+ import com.intellij.openapi.util.Disposer
10
12
import com.intellij.remoteDev.util.onTerminationOrNow
11
13
import com.intellij.util.application
12
- import com.jetbrains.codeWithMe.model.RdPortType
14
+ import com.jetbrains.rd.platform. codeWithMe.portForwarding.*
13
15
import com.jetbrains.rd.platform.util.lifetime
14
16
import com.jetbrains.rd.util.lifetime.LifetimeStatus
15
- import com.jetbrains.rdserver.portForwarding.ForwardedPortInfo
16
- import com.jetbrains.rdserver.portForwarding.PortForwardingManager
17
- import com.jetbrains.rdserver.portForwarding.remoteDev.PortEventsProcessor
18
17
import io.gitpod.jetbrains.remote.GitpodManager
19
18
import io.gitpod.jetbrains.remote.GitpodPortsService
20
19
import io.gitpod.supervisor.api.Status
@@ -24,14 +23,17 @@ import io.grpc.stub.ClientResponseObserver
24
23
import io.ktor.utils.io.*
25
24
import java.util.concurrent.CompletableFuture
26
25
import java.util.concurrent.TimeUnit
26
+ import javax.swing.Icon
27
27
28
28
@Suppress(" UnstableApiUsage" )
29
- class GitpodPortForwardingService (private val project : Project ) {
29
+ class GitpodPortForwardingService (private val session : ClientProjectSession ) {
30
30
companion object {
31
31
const val FORWARDED_PORT_LABEL = " gitpod"
32
32
}
33
33
34
34
private val portsService = service<GitpodPortsService >()
35
+ private val perClientPortForwardingManager = service<PerClientPortForwardingManager >()
36
+ private val portToDisposableMap = mutableMapOf<Int ,Disposable >()
35
37
36
38
init { start() }
37
39
@@ -42,7 +44,7 @@ class GitpodPortForwardingService(private val project: Project) {
42
44
}
43
45
44
46
private fun observePortsListWhileProjectIsOpen () = application.executeOnPooledThread {
45
- while (project.lifetime.status == LifetimeStatus .Alive ) {
47
+ while (session. project.lifetime.status == LifetimeStatus .Alive ) {
46
48
try {
47
49
observePortsList().get()
48
50
} catch (throwable: Throwable ) {
@@ -70,7 +72,7 @@ class GitpodPortForwardingService(private val project: Project) {
70
72
val portsStatusResponseObserver = object :
71
73
ClientResponseObserver <Status .PortsStatusRequest , Status .PortsStatusResponse > {
72
74
override fun beforeStart (request : ClientCallStreamObserver <Status .PortsStatusRequest >) {
73
- project.lifetime.onTerminationOrNow { request.cancel(" gitpod: Project terminated." , null ) }
75
+ session. project.lifetime.onTerminationOrNow { request.cancel(" gitpod: Project terminated." , null ) }
74
76
}
75
77
override fun onNext (response : Status .PortsStatusResponse ) {
76
78
application.invokeLater { updateForwardedPortsList(response) }
@@ -85,48 +87,87 @@ class GitpodPortForwardingService(private val project: Project) {
85
87
}
86
88
87
89
private fun updateForwardedPortsList (response : Status .PortsStatusResponse ) {
88
- val portForwardingManager = PortForwardingManager .getInstance(project)
89
- val forwardedPortsList = portForwardingManager.getForwardedPortsWithLabel(FORWARDED_PORT_LABEL )
90
-
91
90
for (port in response.portsList) {
92
91
val hostPort = port.localPort
93
92
val isServed = port.served
94
- val isForwarded = forwardedPortsList.find { it. hostPort == hostPort } != null
93
+ val isForwarded = perClientPortForwardingManager.getPorts( hostPort).isNotEmpty()
95
94
96
95
if (isServed && ! isForwarded) {
97
- val portEventsProcessor = object : PortEventsProcessor {
98
- override fun onPortForwarded (hostPort : Int , clientPort : Int ) {
99
- portsService.setForwardedPort(hostPort, clientPort)
100
- thisLogger().info(" gitpod: Forwarded port $hostPort to client's port $clientPort ." )
96
+ val forwardedPortListener = object : ForwardedPortListener {
97
+ override fun becameReadOnly (port : ForwardedPort , reason : String? ) {
98
+ thisLogger().warn(" gitpod: becameReadOnly($port , $reason )" )
99
+ }
100
+
101
+ override fun descriptionChanged (port : ForwardedPort , oldDescription : String? , newDescription : String? ) {
102
+ thisLogger().warn(" gitpod: descriptionChanged($port , $oldDescription , $newDescription )" )
103
+ }
104
+
105
+ override fun exposedUrlChanged (port : ForwardedPort , newUrl : String ) {
106
+ thisLogger().warn(" gitpod: exposedUrlChanged($port , $newUrl )" )
107
+ }
108
+
109
+ override fun iconChanged (port : ForwardedPort , oldIcon : Icon ? , newIcon : Icon ? ) {
110
+ thisLogger().warn(" gitpod: iconChanged($port , $oldIcon , $newIcon )" )
101
111
}
102
112
103
- override fun onPortForwardingEnded ( hostPort : Int ) {
104
- thisLogger().info (" gitpod: Finished forwarding port $hostPort . " )
113
+ override fun nameChanged ( port : ForwardedPort , oldName : String? , newName : String? ) {
114
+ thisLogger().warn (" gitpod: nameChanged( $ port, $oldName , $newName ) " )
105
115
}
106
116
107
- override fun onPortForwardingFailed (hostPort : Int , reason : String ) {
108
- thisLogger().error(" gitpod: Failed to forward port $hostPort : $reason " )
117
+ override fun stateChanged (port : ForwardedPort , newState : ClientPortState ) {
118
+ when (newState) {
119
+ is ClientPortState .Assigned -> {
120
+ thisLogger().warn(" gitpod: Started forwarding host port $hostPort to client port ${newState.clientPort} ." )
121
+ portsService.setForwardedPort(hostPort, newState.clientPort)
122
+ }
123
+ is ClientPortState .FailedToAssign -> {
124
+ thisLogger().warn(" gitpod: Detected that host port $hostPort failed to be assigned to a client port." )
125
+ }
126
+ else -> {
127
+ thisLogger().warn(" gitpod: Detected that host port $hostPort is not assigned to any client port." )
128
+ }
129
+ }
130
+ }
131
+
132
+ override fun tooltipChanged (port : ForwardedPort , oldTooltip : String? , newTooltip : String? ) {
133
+ thisLogger().warn(" gitpod: tooltipChanged($port , $oldTooltip , $newTooltip )" )
109
134
}
110
135
}
111
136
112
- val portInfo = ForwardedPortInfo (
137
+ try {
138
+ val forwardedPort = perClientPortForwardingManager.forwardPort(
113
139
hostPort,
114
- RdPortType .HTTP ,
115
- port.exposed.url,
116
- port.name,
117
- port.description,
140
+ PortType .TCP ,
118
141
setOf (FORWARDED_PORT_LABEL ),
119
- emptyList(),
120
- portEventsProcessor
121
- )
142
+ hostPort,
143
+ ClientPortPickingStrategy .REASSIGN_WHEN_BUSY ,
144
+ fun (portPresentation : PortPresentation ) {
145
+ portPresentation.name = port.name
146
+ portPresentation.description = port.description
147
+ portPresentation.icon = null
148
+ portPresentation.tooltip = " Forwarded Port"
149
+ }
150
+ )
151
+
152
+ val portListenerDisposable = portToDisposableMap.getOrPut(hostPort, fun () = Disposer .newDisposable())
122
153
123
- portForwardingManager.forwardPort(portInfo)
154
+ forwardedPort.addPortListener(portListenerDisposable, forwardedPortListener)
155
+ } catch (error: Error ) {
156
+ thisLogger().warn(" gitpod: ${error.message} " )
157
+ }
124
158
}
125
159
126
160
if (! isServed && isForwarded) {
127
- portForwardingManager.removePort(hostPort)
161
+ val portListenerDisposable = portToDisposableMap[hostPort]
162
+ if (portListenerDisposable != null ) {
163
+ portListenerDisposable.dispose()
164
+ portToDisposableMap.remove(hostPort)
165
+ }
166
+ perClientPortForwardingManager.getPorts(hostPort).forEach { portToRemove ->
167
+ perClientPortForwardingManager.removePort(portToRemove)
168
+ }
128
169
portsService.removeForwardedPort(hostPort)
129
- thisLogger().info (" gitpod: Stopped forwarding port $hostPort ." )
170
+ thisLogger().warn (" gitpod: Stopped forwarding port $hostPort ." )
130
171
}
131
172
}
132
173
}
0 commit comments