Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wrote ssh exception handler #228

Merged
merged 10 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 26 additions & 17 deletions src/main/kotlin/com/vk/admstorm/ssh/SshConnectionService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import com.intellij.remote.RemoteConnector
import com.intellij.remote.RemoteCredentials
import com.intellij.ssh.ConnectionBuilder
import com.intellij.ssh.ExecBuilder
import com.intellij.ssh.SshException
import com.intellij.ssh.channels.SftpChannel
import com.intellij.ssh.connectionBuilder
import com.jetbrains.plugins.remotesdk.console.SshConfigConnector
Expand All @@ -24,9 +23,11 @@ import com.vk.admstorm.transfer.TransferService
import com.vk.admstorm.utils.MySshUtils
import com.vk.admstorm.utils.MyUtils.executeOnPooledThread
import git4idea.util.GitUIUtil.code
import net.schmizz.sshj.connection.channel.OpenFailException
import net.schmizz.sshj.sftp.SFTPClient
import java.io.IOException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException

/**
* Service responsible for connecting via SSH to the development server.
Expand Down Expand Up @@ -144,24 +145,15 @@ class SshConnectionService(private var myProject: Project) : Disposable {

override fun run(indicator: ProgressIndicator) {
try {
mySftpChannel = myConnectionBuilder!!.openSftpChannel(2)
mySftpClient = MySshUtils.getSftpClient(mySftpChannel!!)
SshHandler.handle {
mySftpChannel = myConnectionBuilder!!.openSftpChannel(2)
mySftpClient = MySshUtils.getSftpClient(mySftpChannel!!)

onSuccessful?.run()
} catch (e: SshException) {
if (!cancelled && e.message == "Cancelled by user") {
LOG.warn("Cancelled by user", e)
return
onSuccessful?.run()
}

val exceptionMessage = e.message
?.removePrefix("java.net.SocketTimeoutException: ")
?.replaceFirstChar { it.uppercaseChar() }
?.plus("<br>")
?: ""

} catch (ex: OpenFailException) {
val message =
"${exceptionMessage}Plugin can try to automatically reset the Yubikey or you can do it yourself with ${
"${ex.message}<br> Plugin can try to automatically reset the Yubikey or you can do it yourself with ${
code("ssh-agent")
}"

Expand All @@ -185,7 +177,24 @@ class SshConnectionService(private var myProject: Project) : Disposable {
})
.show()

LOG.warn("Failed to connect", e)
LOG.warn("Failed to connect", ex)
} catch (ex: TimeoutException) {
if (indicator.isCanceled) {
LOG.info("Cancelled by user", ex)
return
}

AdmNotification("Don't forget to touch the yubikey if it blinks when using the AdmStorm plugin's features")
.withTitle("Yubikey waiting timeout")
.withActions(AdmNotification.Action("Reconnect...") { _, notification ->
notification.expire()
connectWithConnector(connector, onSuccessful)
}).show()

LOG.info("Yubikey waiting timeout", ex)
} catch (ex: Exception) {
LOG.error("Unhandled exception ${ex.javaClass.name}")
return
}
}

Expand Down
22 changes: 22 additions & 0 deletions src/main/kotlin/com/vk/admstorm/ssh/SshHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.vk.admstorm.ssh

import com.intellij.ssh.SshException

object SshHandler {
inline fun <reified T> handle(call: () -> T): T {
return try {
call()
} catch (ex: SshException) {
throw unwrap(ex)
}
}

fun unwrap(ex: Exception): Throwable {
var cause = ex.cause
while (cause?.cause != null) {
cause = cause.cause
}

return cause?: ex
}
}
42 changes: 19 additions & 23 deletions src/main/kotlin/com/vk/admstorm/utils/MySshUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.remote.ColoredRemoteProcessHandler
import com.intellij.ssh.ExecBuilder
import com.intellij.ssh.SshException
import com.intellij.ssh.channels.SftpChannel
import com.intellij.ssh.process.SshExecProcess
import com.intellij.util.ReflectionUtil
Expand All @@ -16,9 +15,11 @@ import com.vk.admstorm.notifications.AdmErrorNotification
import com.vk.admstorm.notifications.AdmNotification
import com.vk.admstorm.notifications.AdmWarningNotification
import com.vk.admstorm.ssh.SshConnectionService
import com.vk.admstorm.ssh.SshHandler
import com.vk.admstorm.ssh.YubikeyHandler
import com.vk.admstorm.utils.MyUtils.executeOnPooledThread
import git4idea.util.GitUIUtil.code
import net.schmizz.sshj.connection.channel.OpenFailException
import net.schmizz.sshj.sftp.SFTPClient
import java.lang.reflect.Field
import java.nio.charset.Charset
Expand Down Expand Up @@ -85,21 +86,23 @@ object MySshUtils {
}

val process = try {
execSync(builder)
} catch (e: SshException) {
handleSshException(project, e)
SshHandler.handle {
execSync(builder)
}
} catch (ex: OpenFailException) {
handleSshException(project, ex)
null
} catch (e: TimeoutException) {
} catch (ex: TimeoutException) {
AdmWarningNotification("Don't forget to touch the yubikey if it blinks when using the AdmStorm plugin's features")
.withTitle("Yubikey waiting timeout")
.show()
LOG.warn("Yubikey waiting timeout", e)
LOG.info("Yubikey waiting timeout", ex)
null
} catch (e: IllegalStateException) {
handleSshException(project, e)
} catch (ex: IllegalStateException) {
handleSshException(project, ex)
null
} catch (e: Exception) {
handleSshException(project, e)
} catch (ex: Exception) {
LOG.error("Unhandled exception ${ex.javaClass.name}")
null
} ?: return null

Expand All @@ -109,17 +112,11 @@ object MySshUtils {
return ColoredRemoteProcessHandler(process, firstLine, Charset.defaultCharset())
}

private fun handleSshException(project: Project, e: Exception) {
val exceptionMessage = e.message
?.removePrefix("java.net.SocketTimeoutException: ")
?.replaceFirstChar { it.uppercaseChar() }
?.plus("<br>")
?: ""

val message = """
${exceptionMessage}Plugin can try to automatically reset the Yubikey and reconnect or you can do it
yourself with ${code("ssh-agent")} and push 'Reconnect' button.
""".trimIndent()
private fun handleSshException(project: Project, ex: Exception) {
val message =
"${ex.message}<br> Plugin can try to automatically reset the Yubikey or you can do it yourself with ${
code("ssh-agent")
}"

AdmWarningNotification(message)
.withTitle("SSH connection lost")
Expand All @@ -144,8 +141,7 @@ object MySshUtils {
}
)
.show()

LOG.warn("Unexpected exception for execSync(builder)", e)
LOG.warn("Unexpected exception for execSync(builder)", ex)
}

private fun execSync(builder: ExecBuilder): SshExecProcess {
Expand Down
Loading