@@ -7,6 +7,7 @@ import com.coder.toolbox.sdk.CoderRestClient
7
7
import com.coder.toolbox.sdk.ex.APIResponseException
8
8
import com.coder.toolbox.sdk.v2.models.Workspace
9
9
import com.coder.toolbox.sdk.v2.models.WorkspaceAgent
10
+ import com.coder.toolbox.util.waitForFalseWithTimeout
10
11
import com.coder.toolbox.util.withPath
11
12
import com.coder.toolbox.views.Action
12
13
import com.coder.toolbox.views.EnvironmentView
@@ -43,6 +44,10 @@ class CoderRemoteEnvironment(
43
44
private var wsRawStatus = WorkspaceAndAgentStatus .from(workspace, agent)
44
45
45
46
override var name: String = " ${workspace.name} .${agent.name} "
47
+
48
+ private var isConnected: MutableStateFlow <Boolean > = MutableStateFlow (false )
49
+ override val connectionRequest: MutableStateFlow <Boolean > = MutableStateFlow (false )
50
+
46
51
override val state: MutableStateFlow <RemoteEnvironmentState > =
47
52
MutableStateFlow (wsRawStatus.toRemoteEnvironmentState(context))
48
53
override val description: MutableStateFlow <EnvironmentDescription > =
@@ -106,6 +111,8 @@ class CoderRemoteEnvironment(
106
111
} else {
107
112
actions.add(Action (context.i18n.ptrl(" Stop" )) {
108
113
context.cs.launch {
114
+ tryStopSshConnection()
115
+
109
116
val build = client.stopWorkspace(workspace)
110
117
update(workspace.copy(latestBuild = build), agent)
111
118
}
@@ -115,18 +122,30 @@ class CoderRemoteEnvironment(
115
122
return actions
116
123
}
117
124
125
+ private suspend fun tryStopSshConnection () {
126
+ if (isConnected.value) {
127
+ connectionRequest.update {
128
+ false
129
+ }
130
+
131
+ if (isConnected.waitForFalseWithTimeout(10 .seconds) == null ) {
132
+ context.logger.warn(" The SSH connection to workspace $name could not be dropped in time, going to stop the workspace while the SSH connection is live" )
133
+ }
134
+ }
135
+ }
136
+
118
137
override fun getBeforeConnectionHooks (): List <BeforeConnectionHook > = listOf (this )
119
138
120
139
override fun getAfterDisconnectHooks (): List <AfterDisconnectHook > = listOf (this )
121
140
122
141
override fun beforeConnection () {
123
142
context.logger.info(" Connecting to $id ..." )
124
- this . isConnected = true
143
+ isConnected.update { true }
125
144
}
126
145
127
146
override fun afterDisconnect () {
128
147
this .connectionRequest.update { false }
129
- this . isConnected = false
148
+ isConnected.update { false }
130
149
context.logger.info(" Disconnected from $id " )
131
150
}
132
151
@@ -161,17 +180,14 @@ class CoderRemoteEnvironment(
161
180
agent
162
181
)
163
182
164
- private var isConnected = false
165
- override val connectionRequest: MutableStateFlow <Boolean > = MutableStateFlow (false )
166
-
167
183
/* *
168
184
* Does nothing. In theory, we could do something like start the workspace
169
185
* when you click into the workspace, but you would still need to press
170
186
* "connect" anyway before the content is populated so there does not seem
171
187
* to be much value.
172
188
*/
173
189
override fun setVisible (visibilityState : EnvironmentVisibilityState ) {
174
- if (wsRawStatus.ready() && visibilityState.contentsVisible == true && isConnected == false ) {
190
+ if (wsRawStatus.ready() && visibilityState.contentsVisible == true && isConnected.value == false ) {
175
191
context.cs.launch {
176
192
connectionRequest.update {
177
193
true
0 commit comments