@@ -76,6 +76,7 @@ import java.awt.event.MouseListener
7676import java.awt.event.MouseMotionListener
7777import java.awt.font.TextAttribute
7878import java.awt.font.TextAttribute.UNDERLINE_ON
79+ import java.net.SocketTimeoutException
7980import javax.swing.Icon
8081import javax.swing.JTable
8182import javax.swing.JTextField
@@ -211,12 +212,12 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
211212 tfUrl = textField().resizableColumn().align(AlignX .FILL ).gap(RightGap .SMALL ).bindText(localWizardModel::coderURL).applyToComponent {
212213 addActionListener {
213214 poller?.cancel()
214- askTokenAndOpenSession()
215+ askTokenAndOpenSession(true )
215216 }
216217 }.component
217218 button(CoderGatewayBundle .message(" gateway.connector.view.coder.workspaces.connect.text" )) {
218219 poller?.cancel()
219- askTokenAndOpenSession()
220+ askTokenAndOpenSession(true )
220221 }.applyToComponent {
221222 background = WelcomeScreenUIManager .getMainAssociatedComponentBackground()
222223 }
@@ -318,25 +319,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
318319 localWizardModel.coderURL = url
319320 localWizardModel.token = token
320321 tfUrl?.text = url
321-
322- poller?.cancel()
323- try {
324- coderClient.initClientSession(url.toURL(), token)
325- loginAndLoadWorkspace(token)
326- } catch (e: Exception ) {
327- when (e) {
328- is AuthenticationResponseException -> {
329- // probably the token is expired
330- askTokenAndOpenSession()
331- }
332-
333- else -> {
334- logger.warn(" An exception was encountered while opening ${localWizardModel.coderURL} . Reason: ${e.message} " )
335- localWizardModel.token = " "
336- }
337- }
338-
339- }
322+ loginAndLoadWorkspace(token, true )
340323 }
341324 }
342325 updateWorkspaceActions()
@@ -374,49 +357,44 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
374357 ActivityTracker .getInstance().inc()
375358 }
376359
377- private fun askTokenAndOpenSession () {
360+ private fun askTokenAndOpenSession (openBrowser : Boolean ) {
378361 // force bindings to be filled
379362 component.apply ()
380363
381- val pastedToken = askToken()
364+ val pastedToken = askToken(openBrowser )
382365 if (pastedToken.isNullOrBlank()) {
383366 return
384367 }
385- loginAndLoadWorkspace(pastedToken)
368+ // False so that subsequent authentication failures do not keep opening
369+ // the browser as it was already opened earlier.
370+ loginAndLoadWorkspace(pastedToken, false )
386371 }
387372
388- private fun loginAndLoadWorkspace (token : String ) {
389- try {
390- coderClient.initClientSession(localWizardModel.coderURL.toURL(), token)
391- if (! CoderSemVer .isValidVersion(coderClient.buildVersion)) {
392- notificationBanner.apply {
393- component.isVisible = true
394- showWarning(CoderGatewayBundle .message(" gateway.connector.view.coder.workspaces.invalid.coder.version" , coderClient.buildVersion))
395- }
396- } else {
397- val coderVersion = CoderSemVer .parse(coderClient.buildVersion)
398- if (! coderVersion.isInClosedRange(CoderSupportedVersions .minCompatibleCoderVersion, CoderSupportedVersions .maxCompatibleCoderVersion)) {
399- notificationBanner.apply {
400- component.isVisible = true
401- showWarning(CoderGatewayBundle .message(" gateway.connector.view.coder.workspaces.unsupported.coder.version" , coderClient.buildVersion))
402- }
403- }
373+ private fun loginAndLoadWorkspace (token : String , openBrowser : Boolean ) {
374+ LifetimeDefinition ().launchUnderBackgroundProgress(CoderGatewayBundle .message(" gateway.connector.view.coder.workspaces.cli.downloader.dialog.title" ), canBeCancelled = false , isIndeterminate = true ) {
375+ this .indicator.apply {
376+ text = " Authenticating..."
404377 }
405- } catch (e: AuthenticationResponseException ) {
406- logger.error(" Could not authenticate on ${localWizardModel.coderURL} . Reason $e " )
407- return
408- }
409- appPropertiesService.setValue(CODER_URL_KEY , localWizardModel.coderURL)
410- appPropertiesService.setValue(SESSION_TOKEN , token)
411- val cliManager = CoderCLIManager (localWizardModel.coderURL.toURL(), coderClient.buildVersion)
412378
413- localWizardModel.apply {
414- this .token = token
415- buildVersion = coderClient.buildVersion
416- localCliPath = cliManager.localCli.toAbsolutePath().toString()
417- }
379+ try {
380+ authenticate(token)
381+ } catch (e: AuthenticationResponseException ) {
382+ logger.error(" Unable to authenticate to ${localWizardModel.coderURL} ; has your token expired?" , e)
383+ askTokenAndOpenSession(openBrowser)
384+ return @launchUnderBackgroundProgress
385+ } catch (e: SocketTimeoutException ) {
386+ logger.error(" Unable to connect to ${localWizardModel.coderURL} ; is it up?" , e)
387+ return @launchUnderBackgroundProgress
388+ }
389+
390+ val cliManager = CoderCLIManager (localWizardModel.coderURL.toURL(), coderClient.buildVersion)
391+
392+ localWizardModel.apply {
393+ this .token = token
394+ buildVersion = coderClient.buildVersion
395+ localCliPath = cliManager.localCli.toAbsolutePath().toString()
396+ }
418397
419- LifetimeDefinition ().launchUnderBackgroundProgress(CoderGatewayBundle .message(" gateway.connector.view.coder.workspaces.cli.downloader.dialog.title" ), canBeCancelled = false , isIndeterminate = true ) {
420398 this .indicator.apply {
421399 isIndeterminate = false
422400 text = " Retrieving Workspaces..."
@@ -460,16 +438,19 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
460438 }
461439 }
462440
463- private fun askToken (): String? {
464- BrowserUtil .browse(localWizardModel.coderURL.toURL().withPath(" /login?redirect=%2Fcli-auth" ))
441+ private fun askToken (openBrowser : Boolean ): String? {
442+ val getTokenUrl = localWizardModel.coderURL.toURL().withPath(" /login?redirect=%2Fcli-auth" )
443+ if (openBrowser) {
444+ BrowserUtil .browse(getTokenUrl)
445+ }
465446 var tokenFromUser: String? = null
466447 ApplicationManager .getApplication().invokeAndWait({
467448 lateinit var sessionTokenTextField: JBTextField
468449
469450 val panel = panel {
470451 row {
471- label (CoderGatewayBundle .message(" gateway.connector.view.login.token.label" ))
472- sessionTokenTextField = textField().applyToComponent {
452+ browserLink (CoderGatewayBundle .message(" gateway.connector.view.login.token.label" ), getTokenUrl.toString( ))
453+ sessionTokenTextField = textField().bindText(localWizardModel::token). applyToComponent {
473454 minimumSize = Dimension (320 , - 1 )
474455 }.component
475456 }
@@ -495,6 +476,33 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
495476 }
496477 }
497478
479+ /* *
480+ * Check that the token is valid for the URL in the wizard and throw if not.
481+ * On success store the URL and token and display warning banners if
482+ * versions do not match.
483+ */
484+ private fun authenticate (token : String ) {
485+ coderClient.initClientSession(localWizardModel.coderURL.toURL(), token)
486+
487+ if (! CoderSemVer .isValidVersion(coderClient.buildVersion)) {
488+ notificationBanner.apply {
489+ component.isVisible = true
490+ showWarning(CoderGatewayBundle .message(" gateway.connector.view.coder.workspaces.invalid.coder.version" , coderClient.buildVersion))
491+ }
492+ } else {
493+ val coderVersion = CoderSemVer .parse(coderClient.buildVersion)
494+ if (! coderVersion.isInClosedRange(CoderSupportedVersions .minCompatibleCoderVersion, CoderSupportedVersions .maxCompatibleCoderVersion)) {
495+ notificationBanner.apply {
496+ component.isVisible = true
497+ showWarning(CoderGatewayBundle .message(" gateway.connector.view.coder.workspaces.unsupported.coder.version" , coderClient.buildVersion))
498+ }
499+ }
500+ }
501+
502+ appPropertiesService.setValue(CODER_URL_KEY , localWizardModel.coderURL)
503+ appPropertiesService.setValue(SESSION_TOKEN , token)
504+ }
505+
498506 private suspend fun loadWorkspaces () {
499507 val ws = withContext(Dispatchers .IO ) {
500508 val timeBeforeRequestingWorkspaces = System .currentTimeMillis()
@@ -813,4 +821,4 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
813821 companion object {
814822 val logger = Logger .getInstance(CoderWorkspacesStepView ::class .java.simpleName)
815823 }
816- }
824+ }
0 commit comments