Skip to content

Commit

Permalink
fix: startup synchronization in language server in multi-project scen…
Browse files Browse the repository at this point in the history
…ario (#519)
  • Loading branch information
bastiandoetsch authored Apr 26, 2024
1 parent b8225e1 commit acbb617
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 18 deletions.
22 changes: 14 additions & 8 deletions src/main/kotlin/io/snyk/plugin/services/SnykTaskQueueService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import snyk.common.SnykError
import snyk.common.lsp.LanguageServerWrapper
import snyk.trust.confirmScanningAndSetWorkspaceTrustedStateIfNeeded

@Service
@Service(Service.Level.PROJECT)
class SnykTaskQueueService(val project: Project) {
private val logger = logger<SnykTaskQueueService>()
private val taskQueue = BackgroundTaskQueue(project, "Snyk")
Expand Down Expand Up @@ -81,23 +81,29 @@ class SnykTaskQueueService(val project: Project) {
}

fun connectProjectToLanguageServer(project: Project) {
synchronized(LanguageServerWrapper) {

// subscribe to the settings changed topic
getSnykToolWindowPanel(project)?.let {
val languageServerWrapper = LanguageServerWrapper.getInstance()
getSnykToolWindowPanel(project)?.let {
project.messageBus.connect(it)
.subscribe(
SnykSettingsListener.SNYK_SETTINGS_TOPIC,
object : SnykSettingsListener {
override fun settingsChanged() {
val wrapper = LanguageServerWrapper.getInstance()
wrapper.updateConfiguration()
languageServerWrapper.updateConfiguration()
}
}
)
}
LanguageServerWrapper.getInstance().addContentRoots(project)
}
// Try to connect project for up to 30s
for (tries in 1..300) {
if (!languageServerWrapper.isInitialized) {
Thread.sleep(100)
continue
}

languageServerWrapper.addContentRoots(project)
break
}
}

fun scan(isStartup: Boolean) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,15 +542,16 @@ class SnykToolWindowPanel(val project: Project) : JPanel(), Disposable {

private fun enableCodeScanAccordingToServerSetting() {
pluginSettings().apply {
val sastSettings = try {
getSnykApiService().getSastSettings()
} catch (ignored: ClientException) {
null
try {
// update settings if we get a valid/correct response, else log the error and do nothing
val sastSettings = getSnykApiService().getSastSettings()
sastOnServerEnabled = sastSettings?.sastEnabled
val codeScanAllowed = sastOnServerEnabled == true
snykCodeSecurityIssuesScanEnable = snykCodeSecurityIssuesScanEnable && codeScanAllowed
snykCodeQualityIssuesScanEnable = snykCodeQualityIssuesScanEnable && codeScanAllowed
} catch (clientException: ClientException) {
logger.error(clientException)
}
sastOnServerEnabled = sastSettings?.sastEnabled
val codeScanAllowed = sastOnServerEnabled == true
snykCodeSecurityIssuesScanEnable = this.snykCodeSecurityIssuesScanEnable && codeScanAllowed
snykCodeQualityIssuesScanEnable = this.snykCodeQualityIssuesScanEnable && codeScanAllowed
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/main/kotlin/snyk/common/lsp/LanguageServerWrapper.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package snyk.common.lsp

import com.google.common.util.concurrent.CycleDetectingLockFactory
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
Expand Down Expand Up @@ -85,7 +86,9 @@ class LanguageServerWrapper(
*/
lateinit var process: Process

private var isInitializing: ReentrantLock = ReentrantLock()
private var isInitializing: ReentrantLock =
CycleDetectingLockFactory.newInstance(CycleDetectingLockFactory.Policies.THROW)
.newReentrantLock("initializeLock")

internal val isInitialized: Boolean
get() = ::languageClient.isInitialized &&
Expand Down Expand Up @@ -133,6 +136,7 @@ class LanguageServerWrapper(

fun shutdown(): Future<*> {
return executorService.submit {
logger.info("Shutting down Language Server...")
process.destroyForcibly()
}
}
Expand Down Expand Up @@ -231,6 +235,7 @@ class LanguageServerWrapper(
fun ensureLanguageServerInitialized(): Boolean {
if (!isInitialized) {
try {
assert(isInitializing.holdCount == 0)
isInitializing.lock()
initialize()
} finally {
Expand Down Expand Up @@ -340,7 +345,7 @@ class LanguageServerWrapper(
}

fun addContentRoots(project: Project) {
if (!isInitialized) return
assert(isInitialized)
ensureLanguageServerProtocolVersion(project)
val added = getWorkspaceFolders(project)
updateWorkspaceFolders(added, emptySet())
Expand Down

0 comments on commit acbb617

Please sign in to comment.