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