Skip to content

Commit

Permalink
fix: improve startup handling
Browse files Browse the repository at this point in the history
  • Loading branch information
bastiandoetsch committed Jan 30, 2024
1 parent 18ed36e commit 13e806c
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 34 deletions.
1 change: 1 addition & 0 deletions src/main/kotlin/io/snyk/plugin/SnykPostStartupActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class SnykPostStartupActivity : ProjectActivity {
getAnalyticsScanListener(project)?.initScanListener()
} catch (ignored: Exception) {
// do nothing to not break UX for analytics
ignored.printStackTrace()

Check warning

Code scanning / detekt

Do not print a stack trace. These debug statements should be removed or replaced with a logger. Warning

Do not print a stack trace. These debug statements should be removed or replaced with a logger.
}
}

Expand Down
13 changes: 3 additions & 10 deletions src/main/kotlin/io/snyk/plugin/services/SnykTaskQueueService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,10 @@ class SnykTaskQueueService(val project: Project) {
})
}

@OptIn(DelicateCoroutinesApi::class)
fun connectProjectToLanguageServer(project: Project) {
synchronized(ls) {
if (!ls.isInitialized) {
if (!ls.isInitialized && !ls.isInitializing) {
ls.initialize()
GlobalScope.launch {
ls.process.errorStream.bufferedReader().forEachLine { println(it) }
}
GlobalScope.launch {
ls.startListening()
}
}
}
val addedWorkspaceFolders = ProjectRootManager.getInstance(project).contentRoots
Expand Down Expand Up @@ -134,7 +127,7 @@ class SnykTaskQueueService(val project: Project) {
do {
indicator.checkCanceled()
Thread.sleep(WAIT_FOR_DOWNLOAD_MILLIS)
} while (isCliDownloading())
} while (!isCliInstalled() || isCliDownloading())
}

private fun scheduleContainerScan() {
Expand Down Expand Up @@ -328,7 +321,7 @@ class SnykTaskQueueService(val project: Project) {
}

companion object {
private const val WAIT_FOR_DOWNLOAD_MILLIS = 500L
private const val WAIT_FOR_DOWNLOAD_MILLIS = 1000L
val ls = LanguageServerWrapper()
}
}
74 changes: 50 additions & 24 deletions src/main/kotlin/snyk/common/lsp/LanguageServerWrapper.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package snyk.common.lsp

import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.roots.ProjectRootManager
import io.snyk.plugin.getCliFile
import io.snyk.plugin.pluginSettings
import io.snyk.plugin.snykcode.core.RunUtils
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.eclipse.lsp4j.ClientInfo
import org.eclipse.lsp4j.DidChangeWorkspaceFoldersParams
import org.eclipse.lsp4j.ExecuteCommandParams
Expand All @@ -24,6 +28,7 @@ import java.util.concurrent.TimeUnit

class LanguageServerWrapper(private val lsPath: String = getCliFile().absolutePath) {
private val gson = com.google.gson.Gson()
val logger = Logger.getInstance("Snyk Language Server")

/**
* The language client is used to receive messages from LS
Expand All @@ -46,24 +51,41 @@ class LanguageServerWrapper(private val lsPath: String = getCliFile().absolutePa
*/
lateinit var process: Process

var isInitializing: Boolean = false
val isInitialized: Boolean
get() = ::languageClient.isInitialized && ::languageServer.isInitialized &&
::process.isInitialized && process.info().startInstant().isPresent


@OptIn(DelicateCoroutinesApi::class)

Check warning

Code scanning / detekt

Reports consecutive blank lines Warning

Needless blank line(s)
internal fun initialize() {
val snykLanguageClient = SnykLanguageClient()
languageClient = snykLanguageClient
val logLevel = if (snykLanguageClient.logger.isDebugEnabled) "debug" else "info"
val cmd = listOf(lsPath, "language-server", "-l", logLevel)
try {
isInitializing = true
val snykLanguageClient = SnykLanguageClient()
languageClient = snykLanguageClient
val logLevel = if (snykLanguageClient.logger.isDebugEnabled) "debug" else "info"
val cmd = listOf(lsPath, "language-server", "-l", logLevel)

val processBuilder = ProcessBuilder(cmd)
pluginSettings().token?.let { EnvironmentHelper.updateEnvironment(processBuilder.environment(), it) }
val processBuilder = ProcessBuilder(cmd)
pluginSettings().token?.let { EnvironmentHelper.updateEnvironment(processBuilder.environment(), it) }

process = processBuilder.start()
launcher = LSPLauncher.createClientLauncher(languageClient, process.inputStream, process.outputStream)
languageServer = launcher.remoteProxy
process = processBuilder.start()
launcher = LSPLauncher.createClientLauncher(languageClient, process.inputStream, process.outputStream)
languageServer = launcher.remoteProxy

sendInitializeMessage()
GlobalScope.launch {
process.errorStream.bufferedReader().forEachLine { println(it) }
}
GlobalScope.launch {
launcher.startListening()
}

sendInitializeMessage()
} catch (e: Exception) {

Check warning

Code scanning / detekt

The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled. Warning

The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled.
logger.error(e)
} finally {
isInitializing = false
}
}

private fun determineWorkspaceFolders(): List<WorkspaceFolder> {
Expand All @@ -76,11 +98,6 @@ class LanguageServerWrapper(private val lsPath: String = getCliFile().absolutePa
return workspaceFolders.toList()
}

fun startListening() {
// Start the server
launcher.startListening()
}

fun sendInitializeMessage() {
val workspaceFolders = determineWorkspaceFolders()

Expand All @@ -98,27 +115,36 @@ class LanguageServerWrapper(private val lsPath: String = getCliFile().absolutePa
project,
"Updating workspace folders for project: ${project.name}"
) {
while (!isInitialized) {
Thread.sleep(100)
try {
ensureLanguageServerInitialized()
val params = DidChangeWorkspaceFoldersParams()
params.event = WorkspaceFoldersChangeEvent(added, removed)
languageServer.workspaceService.didChangeWorkspaceFolders(params)
} catch (e: Exception) {

Check warning

Code scanning / detekt

The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled. Warning

The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled.
logger.error(e)
}
val params = DidChangeWorkspaceFoldersParams()
params.event = WorkspaceFoldersChangeEvent(added, removed)
languageServer.workspaceService.didChangeWorkspaceFolders(params)
}
}

fun sendReportAnalyticsCommand(scanDoneEvent: ScanDoneEvent) {
while (!isInitialized) {
private fun ensureLanguageServerInitialized() {
while (isInitializing) {
Thread.sleep(100)

Check warning

Code scanning / detekt

Report magic numbers. Magic number is a numeric literal that is not defined as a constant and hence it's unclear what the purpose of this number is. It's better to declare such numbers as constants and give them a proper name. By default, -1, 0, 1, and 2 are not considered to be magic numbers. Warning

This expression contains a magic number. Consider defining it to a well named constant.
}
if (!isInitialized) {
initialize()
}
}

fun sendReportAnalyticsCommand(scanDoneEvent: ScanDoneEvent) {
ensureLanguageServerInitialized()
try {
val eventString = gson.toJson(scanDoneEvent)
val param = ExecuteCommandParams()
param.command = "snyk.reportAnalytics"
param.arguments = listOf(eventString)
languageServer.workspaceService.executeCommand(param)
} catch (ignored: Exception) {
// do nothing to not break UX for analytics
} catch (e: Exception) {

Check warning

Code scanning / detekt

The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled. Warning

The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled.
logger.error(e)
}
}

Expand Down

0 comments on commit 13e806c

Please sign in to comment.