@@ -20,13 +20,16 @@ import com.jetbrains.toolbox.api.remoteDev.RemoteProvider
2020import  com.jetbrains.toolbox.api.remoteDev.RemoteProviderEnvironment 
2121import  com.jetbrains.toolbox.api.ui.actions.ActionDescription 
2222import  com.jetbrains.toolbox.api.ui.components.UiPage 
23+ import  kotlinx.coroutines.ExperimentalCoroutinesApi 
2324import  kotlinx.coroutines.Job 
24- import  kotlinx.coroutines.delay  
25+ import  kotlinx.coroutines.channels.Channel  
2526import  kotlinx.coroutines.flow.MutableStateFlow 
2627import  kotlinx.coroutines.flow.StateFlow 
2728import  kotlinx.coroutines.flow.update 
2829import  kotlinx.coroutines.isActive 
2930import  kotlinx.coroutines.launch 
31+ import  kotlinx.coroutines.selects.onTimeout 
32+ import  kotlinx.coroutines.selects.select 
3033import  okhttp3.OkHttpClient 
3134import  java.net.URI 
3235import  java.net.URL 
@@ -35,18 +38,20 @@ import kotlin.time.Duration.Companion.seconds
3538import  com.jetbrains.toolbox.api.ui.components.AccountDropdownField  as  DropDownMenu 
3639import  com.jetbrains.toolbox.api.ui.components.AccountDropdownField  as  dropDownFactory 
3740
41+ @OptIn(ExperimentalCoroutinesApi ::class )
3842class  CoderRemoteProvider (
3943    private  val  context :  CoderToolboxContext ,
4044    private  val  httpClient :  OkHttpClient ,
4145) : RemoteProvider(" Coder" 
4246    //  Current polling job.
4347    private  var  pollJob:  Job ?  =  null 
44-     private  var  lastEnvironments:   Set <CoderRemoteEnvironment >?   =   null 
48+     private  val  lastEnvironments  =  mutableSetOf <CoderRemoteEnvironment >() 
4549
46-     private  val  cSettings  =  context.settingsStore.readOnly()
50+     private  val  settings  =  context.settingsStore.readOnly()
4751
4852    //  Create our services from the Toolbox ones.
49-     private  val  settingsPage:  CoderSettingsPage  =  CoderSettingsPage (context)
53+     private  val  triggerSshConfig =  Channel <Boolean >(Channel .CONFLATED )
54+     private  val  settingsPage:  CoderSettingsPage  =  CoderSettingsPage (context, triggerSshConfig)
5055    private  val  dialogUi =  DialogUi (context)
5156
5257    //  The REST client, if we are signed in
@@ -92,7 +97,7 @@ class CoderRemoteProvider(
9297                        }?.map { agent -> 
9398                            //  If we have an environment already, update that.
9499                            val  env =  CoderRemoteEnvironment (context, client, ws, agent)
95-                             lastEnvironments? .firstOrNull { it ==  env }?.let  {
100+                             lastEnvironments.firstOrNull { it ==  env }?.let  {
96101                                it.update(ws, agent)
97102                                it
98103                            } ? :  env
@@ -107,9 +112,7 @@ class CoderRemoteProvider(
107112
108113                //  Reconfigure if a new environment is found.
109114                //  TODO@JB: Should we use the add/remove listeners instead?
110-                 val  newEnvironments =  lastEnvironments
111-                     ?.let  { resolvedEnvironments.subtract(it) }
112-                     ? :  resolvedEnvironments
115+                 val  newEnvironments =  resolvedEnvironments.subtract(lastEnvironments)
113116                if  (newEnvironments.isNotEmpty()) {
114117                    context.logger.info(" Found new environment(s), reconfiguring CLI: $newEnvironments " 
115118                    cli.configSsh(newEnvironments.map { it.name }.toSet())
@@ -124,8 +127,10 @@ class CoderRemoteProvider(
124127                        true 
125128                    }
126129                }
127- 
128-                 lastEnvironments =  resolvedEnvironments
130+                 lastEnvironments.apply  {
131+                     clear()
132+                     addAll(resolvedEnvironments)
133+                 }
129134            } catch  (_:  CancellationException ) {
130135                context.logger.debug(" ${client.url}  polling loop canceled" 
131136                break 
@@ -136,7 +141,17 @@ class CoderRemoteProvider(
136141                break 
137142            }
138143            //  TODO: Listening on a web socket might be better?
139-             delay(5 .seconds)
144+             select<Unit > {
145+                 onTimeout(5 .seconds) {
146+                     context.logger.trace(" workspace poller waked up by the 5 seconds timeout" 
147+                 }
148+                 triggerSshConfig.onReceive { shouldTrigger -> 
149+                     if  (shouldTrigger) {
150+                         context.logger.trace(" workspace poller waked up because it should reconfigure the ssh configurations" 
151+                         cli.configSsh(lastEnvironments.map { it.name }.toSet())
152+                     }
153+                 }
154+             }
140155        }
141156    }
142157
@@ -178,7 +193,7 @@ class CoderRemoteProvider(
178193    override  fun  close () {
179194        pollJob?.cancel()
180195        client?.close()
181-         lastEnvironments  =   null 
196+         lastEnvironments.clear() 
182197        environments.value =  LoadableState .Value (emptyList())
183198        isInitialized.update { false  }
184199    }
@@ -270,7 +285,7 @@ class CoderRemoteProvider(
270285            var  autologinEx:  Exception ?  =  null 
271286            context.secrets.lastToken.let  { lastToken -> 
272287                context.secrets.lastDeploymentURL.let  { lastDeploymentURL -> 
273-                     if  (autologin &&  lastDeploymentURL.isNotBlank() &&  (lastToken.isNotBlank() ||  ! cSettings .requireTokenAuth)) {
288+                     if  (autologin &&  lastDeploymentURL.isNotBlank() &&  (lastToken.isNotBlank() ||  ! settings .requireTokenAuth)) {
274289                        try  {
275290                            return  createConnectPage(URL (lastDeploymentURL), lastToken)
276291                        } catch  (ex:  Exception ) {
@@ -342,7 +357,7 @@ class CoderRemoteProvider(
342357        if  (it.isNotBlank() &&  context.secrets.lastDeploymentURL ==  deploymentURL.toString()) {
343358            it to SettingSource .LAST_USED 
344359        } else  {
345-             cSettings .token(deploymentURL)
360+             settings .token(deploymentURL)
346361        }
347362    }
348363
0 commit comments