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

Add support for Amazon Q chat on remote 242+ #4825

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 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
6 changes: 6 additions & 0 deletions plugins/amazonq/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
import org.jetbrains.intellij.platform.gradle.tasks.aware.SplitModeAware
import software.aws.toolkits.gradle.changelog.tasks.GeneratePluginChangeLog
import software.aws.toolkits.gradle.intellij.IdeFlavor
import software.aws.toolkits.gradle.intellij.IdeVersions
Expand Down Expand Up @@ -49,3 +50,8 @@ tasks.check {
}
}
}

val runSplitIde by intellijPlatformTesting.runIde.registering {
splitMode = true
splitModeTarget = SplitModeAware.SplitModeTarget.BACKEND
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import software.aws.toolkits.jetbrains.services.amazonq.util.createBrowser
import software.aws.toolkits.jetbrains.utils.isQConnected
import software.aws.toolkits.jetbrains.utils.isQExpired
import software.aws.toolkits.jetbrains.utils.isQWebviewsAvailable

Check warning on line 39 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive
import software.aws.toolkits.telemetry.FeatureId
import software.aws.toolkits.telemetry.UiTelemetry
import software.aws.toolkits.telemetry.WebviewTelemetry
Expand Down Expand Up @@ -86,7 +86,7 @@
}

private fun init() {
if (!isQWebviewsAvailable()) {
if (false) {

Check notice on line 89 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Condition of 'if' expression is constant

Condition is always 'false'

Check notice

Code scanning / QDJVMC

Condition of 'if' expression is constant Note

Condition is always 'false'
// Fallback to an alternative browser-less solution
webviewContainer.add(JBTextArea("JCEF not supported"))
browser = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import software.aws.toolkits.jetbrains.services.amazonq.gettingstarted.openMeetQPage
import software.aws.toolkits.jetbrains.utils.isQConnected
import software.aws.toolkits.jetbrains.utils.isQExpired
import software.aws.toolkits.jetbrains.utils.isQWebviewsAvailable

Check warning on line 33 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive
import software.aws.toolkits.resources.message
import software.aws.toolkits.telemetry.FeatureId
import java.awt.event.ComponentAdapter
Expand Down Expand Up @@ -107,13 +107,13 @@
project: Project,
qPanel: Wrapper,
) {
val component = if (isQConnected(project) && !isQExpired(project)) {
AmazonQToolWindow.getInstance(project).component
} else {
QWebviewPanel.getInstance(project).browser?.prepareBrowser(BrowserState(FeatureId.AmazonQ))
QWebviewPanel.getInstance(project).component
}
qPanel.setContent(component)
// val component = if (isQConnected(project) && !isQExpired(project)) {
qPanel.setContent(AmazonQToolWindow.getInstance(project).component)
// } else {
// QWebviewPanel.getInstance(project).browser?.prepareBrowser(BrowserState(FeatureId.AmazonQ))
// QWebviewPanel.getInstance(project).component
// }
// qPanel.setContent(component)
}

override fun init(toolWindow: ToolWindow) {
Expand All @@ -132,7 +132,7 @@
)
}

override fun shouldBeAvailable(project: Project): Boolean = isQWebviewsAvailable()
override fun shouldBeAvailable(project: Project): Boolean = true

private fun onConnectionChanged(project: Project, newConnection: ToolkitConnection?, qPanel: Wrapper) {
val isNewConnectionForQ = newConnection?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@

package software.aws.toolkits.jetbrains.services.amazonq.util

import com.github.rli.cefschemeremotetest.toolWindow.JBCefLocalRequestHandler

Check warning on line 6 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/util/JcefBrowserUtil.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive

Check warning

Code scanning / QDJVMC

Unused import directive Warning

Unused import directive
import com.github.rli.cefschemeremotetest.toolWindow.JBCefStreamResourceHandler

Check warning on line 7 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/util/JcefBrowserUtil.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive

Check warning

Code scanning / QDJVMC

Unused import directive Warning

Unused import directive
import com.intellij.openapi.Disposable
import com.intellij.openapi.util.Disposer
import com.intellij.ui.jcef.JBCefApp
import com.intellij.ui.jcef.JBCefBrowserBase
import com.intellij.ui.jcef.JBCefBrowserBuilder
import com.intellij.ui.jcef.JBCefClient
import software.aws.toolkits.jetbrains.services.amazonq.webview.AssetResourceHandler

Check warning on line 14 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/util/JcefBrowserUtil.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive

Check warning

Code scanning / QDJVMC

Unused import directive Warning

Unused import directive
import software.aws.toolkits.jetbrains.services.amazonq.webview.Browser

Check warning on line 15 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/util/JcefBrowserUtil.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive

Check warning

Code scanning / QDJVMC

Unused import directive Warning

Unused import directive

fun createBrowser(parent: Disposable): JBCefBrowserBase {
val client = JBCefApp.getInstance().createClient().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
package software.aws.toolkits.jetbrains.services.amazonq.webview

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.github.rli.cefschemeremotetest.toolWindow.JBCefLocalRequestHandler
import com.github.rli.cefschemeremotetest.toolWindow.JBCefStreamResourceHandler
import com.intellij.openapi.Disposable
import com.intellij.openapi.util.Disposer
import com.intellij.ui.jcef.JBCefJSQuery
import org.cef.CefApp

Check warning on line 12 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive
import software.aws.toolkits.jetbrains.services.amazonq.util.HighlightCommand
import software.aws.toolkits.jetbrains.services.amazonq.util.createBrowser
import software.aws.toolkits.jetbrains.settings.MeetQSettings
Expand All @@ -19,7 +21,9 @@

val jcefBrowser = createBrowser(parent)

val receiveMessageQuery = JBCefJSQuery.create(jcefBrowser)
val receiveMessageQuery = JBCefJSQuery.create(jcefBrowser).also {
Disposer.register(this, it)
}

fun init(
isCodeTransformAvailable: Boolean,
Expand All @@ -29,14 +33,6 @@
isCodeTestAvailable: Boolean,
highlightCommand: HighlightCommand?,
) {
// register the scheme handler to route http://mynah/ URIs to the resources/assets directory on classpath
CefApp.getInstance()
.registerSchemeHandlerFactory(
"http",
"mynah",
AssetResourceHandler.AssetResourceHandlerFactory(),
)

loadWebView(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable, highlightCommand)
}

Expand All @@ -63,10 +59,27 @@
// setup empty state. The message request handlers use this for storing state
// that's persistent between page loads.
jcefBrowser.setProperty("state", "")
// load the web app
jcefBrowser.loadHTML(

val handler = JBCefLocalRequestHandler("http", "toolkitasset")
handler.addResource("webview/chat.html") {
getWebviewHTML(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable, highlightCommand)
)
.byteInputStream().let {
JBCefStreamResourceHandler(it, "text/html", this)
}
}

handler.addResource("mynah/js/mynah-ui.js") {
AssetResourceHandler::class.java.getResourceAsStream("/mynah-ui/assets/js/mynah-ui.js")?.let {
JBCefStreamResourceHandler(it, "text/javascript", this)
}
}
jcefBrowser.jbCefClient.addRequestHandler(handler, jcefBrowser.cefBrowser)
Disposer.register(this) {
jcefBrowser.jbCefClient.removeRequestHandler(handler, jcefBrowser.cefBrowser)
}

// load the web app
jcefBrowser.loadURL("http://toolkitasset/webview/chat.html")
}

/**
Expand All @@ -84,7 +97,7 @@
val postMessageToJavaJsCode = receiveMessageQuery.inject("JSON.stringify(message)")

val jsScripts = """
<script type="text/javascript" src="$WEB_SCRIPT_URI" defer onload="init()"></script>
<script type="text/javascript" src="http://toolkitasset/mynah/js/mynah-ui.js" defer onload="init()"></script>
<script type="text/javascript">
const init = () => {
mynahUI.createMynahUI(
Expand Down Expand Up @@ -120,7 +133,6 @@
}

companion object {
private const val WEB_SCRIPT_URI = "http://mynah/js/mynah-ui.js"
private const val MAX_ONBOARDING_PAGE_COUNT = 3
private val OBJECT_MAPPER = jacksonObjectMapper()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@

package software.aws.toolkits.jetbrains.services.cwc.editor.context.file

import com.intellij.idea.AppMode
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.client.ClientKind
import com.intellij.openapi.client.sessions
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Document
import com.intellij.openapi.fileEditor.ClientFileEditorManager
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
Expand All @@ -17,9 +22,13 @@
class FileContextExtractor(private val fqnWebviewAdapter: FqnWebviewAdapter?, private val project: Project) {
private val languageExtractor: LanguageExtractor = LanguageExtractor()
suspend fun extract(): FileContext? {
val editor = computeOnEdt {
FileEditorManager.getInstance(project).selectedTextEditor
} ?: return null
val editor = if (AppMode.isRemoteDevHost()) {

Check warning on line 25 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/file/FileContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'com.intellij.idea.AppMode' is marked unstable with @ApiStatus.Internal

Check warning on line 25 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/file/FileContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'isRemoteDevHost()' is declared in unstable class 'com.intellij.idea.AppMode' marked with @ApiStatus.Internal
project.sessions(ClientKind.REMOTE).firstOrNull()?.service<ClientFileEditorManager>()?.getSelectedTextEditor() ?: return null

Check warning on line 26 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/file/FileContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'getSelectedTextEditor()' is declared in unstable 'com.intellij.openapi.fileEditor.ClientFileEditorManager' marked with @ApiStatus.Internal

Check warning on line 26 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/file/FileContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'REMOTE' is declared in unstable 'com.intellij.openapi.client.ClientKind' marked with @ApiStatus.Experimental

Check warning on line 26 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/file/FileContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'sessions(com.intellij.openapi.project.Project, com.intellij.openapi.client.ClientKind)' is marked unstable with @ApiStatus.Internal

Check warning on line 26 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/file/FileContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'com.intellij.openapi.client.ClientKind' is marked unstable with @ApiStatus.Experimental

Check warning on line 26 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/file/FileContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'com.intellij.openapi.fileEditor.ClientFileEditorManager' is marked unstable with @ApiStatus.Internal
} else {
computeOnEdt {
FileEditorManager.getInstance(project).selectedTextEditor
} ?: return null
}

val fileLanguage = computeOnEdt {
languageExtractor.extractLanguageNameFromCurrentFile(editor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@

package software.aws.toolkits.jetbrains.services.cwc.editor.context.focusArea

import com.intellij.idea.AppMode
import com.intellij.openapi.client.ClientKind
import com.intellij.openapi.client.sessions
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.editor.SelectionModel
import com.intellij.openapi.fileEditor.ClientFileEditorManager
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
Expand All @@ -25,10 +30,13 @@

private val languageExtractor: LanguageExtractor = LanguageExtractor()
suspend fun extract(): FocusAreaContext? {
val editor = computeOnEdt {
FileEditorManager.getInstance(project).selectedTextEditor
} ?: return null

val editor = if (AppMode.isRemoteDevHost()) {

Check warning on line 33 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/focusArea/FocusAreaContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'com.intellij.idea.AppMode' is marked unstable with @ApiStatus.Internal

Check warning on line 33 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/focusArea/FocusAreaContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'isRemoteDevHost()' is declared in unstable class 'com.intellij.idea.AppMode' marked with @ApiStatus.Internal
project.sessions(ClientKind.REMOTE).firstOrNull()?.service<ClientFileEditorManager>()?.getSelectedTextEditor() ?: return null

Check warning on line 34 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/focusArea/FocusAreaContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'getSelectedTextEditor()' is declared in unstable 'com.intellij.openapi.fileEditor.ClientFileEditorManager' marked with @ApiStatus.Internal

Check warning on line 34 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/focusArea/FocusAreaContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'sessions(com.intellij.openapi.project.Project, com.intellij.openapi.client.ClientKind)' is marked unstable with @ApiStatus.Internal

Check warning on line 34 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/focusArea/FocusAreaContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'REMOTE' is declared in unstable 'com.intellij.openapi.client.ClientKind' marked with @ApiStatus.Experimental

Check warning on line 34 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/focusArea/FocusAreaContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'com.intellij.openapi.fileEditor.ClientFileEditorManager' is marked unstable with @ApiStatus.Internal

Check warning on line 34 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/focusArea/FocusAreaContextExtractor.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'com.intellij.openapi.client.ClientKind' is marked unstable with @ApiStatus.Experimental
} else {
computeOnEdt {
FileEditorManager.getInstance(project).selectedTextEditor
} ?: return null
}
if (editor.document.text.isBlank()) return null

// Get 10k characters around the cursor
Expand Down Expand Up @@ -109,7 +117,7 @@
languageExtractor.extractLanguageNameFromCurrentFile(editor)
}
val fileText = editor.document.text
val fileName = FileEditorManager.getInstance(project).selectedFiles.first().name
val fileName = editor.virtualFile.name

// Offset the selection range to the start of the trimmedFileText
val selectionInsideTrimmedFileTextRange = codeSelectionRange.let {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.

package com.github.rli.cefschemeremotetest.toolWindow

Check notice on line 3 in plugins/core/jetbrains-community/src/contrib/org/intellij/images/editor/impl/jcef/JBCefLocalRequestHandler.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Package name does not match containing directory

Package directive does not match the file location

Check notice

Code scanning / QDJVMC

Package name does not match containing directory Note

Package directive does not match the file location

import org.cef.browser.CefBrowser
import org.cef.browser.CefFrame
import org.cef.callback.CefCallback
import org.cef.handler.*
import org.cef.misc.BoolRef
import org.cef.network.CefRequest
import java.net.URL

/**
* Handles local protocol-specific CEF resource requests for a defined `protocol` and `authority`.
*
* This class implements a mechanism to serve protocol-specific resources based on mappings provided
* through the `addResource` function. Only requests matching the configured protocol and authority are processed,
* while others are rejected.
*
* @param myProtocol The protocol to handle (e.g., "http", "file").
* @param myAuthority The authority of the requests (e.g., "localhost", "mydomain").
*/
open class JBCefLocalRequestHandler(
private val myProtocol: String,
private val myAuthority: String
) : CefRequestHandlerAdapter() {
private val myResources: MutableMap<String, () -> CefResourceHandler?> = HashMap()

private val REJECTING_RESOURCE_HANDLER: CefResourceHandler = object : CefResourceHandlerAdapter() {

Check notice on line 29 in plugins/core/jetbrains-community/src/contrib/org/intellij/images/editor/impl/jcef/JBCefLocalRequestHandler.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Private property naming convention

Private property name `REJECTING_RESOURCE_HANDLER` should not contain underscores in the middle or the end

Check notice

Code scanning / QDJVMC

Private property naming convention Note

Private property name REJECTING_RESOURCE_HANDLER should not contain underscores in the middle or the end
override fun processRequest(request: CefRequest, callback: CefCallback): Boolean {
callback.cancel()
return false
}
}

private val RESOURCE_REQUEST_HANDLER = object : CefResourceRequestHandlerAdapter() {

Check notice on line 36 in plugins/core/jetbrains-community/src/contrib/org/intellij/images/editor/impl/jcef/JBCefLocalRequestHandler.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Private property naming convention

Private property name `RESOURCE_REQUEST_HANDLER` should not contain underscores in the middle or the end

Check notice

Code scanning / QDJVMC

Private property naming convention Note

Private property name RESOURCE_REQUEST_HANDLER should not contain underscores in the middle or the end
override fun getResourceHandler(browser: CefBrowser?, frame: CefFrame?, request: CefRequest): CefResourceHandler {
val url = URL(request.url)
url.protocol
if (!url.protocol.equals(myProtocol) || !url.authority.equals(myAuthority)) {
return REJECTING_RESOURCE_HANDLER
}
return try {
val path = url.path.trim('/')
myResources[path]?.let { it() } ?: REJECTING_RESOURCE_HANDLER
} catch (e: RuntimeException) {
println(e.message)
REJECTING_RESOURCE_HANDLER
}
}
}

fun addResource(resourcePath: String, resourceProvider: () -> CefResourceHandler?) {
val normalisedPath = resourcePath.trim('/')
myResources[normalisedPath] = resourceProvider
}

fun createResource(resourcePath: String, resourceProvider: () -> CefResourceHandler?): String {

Check warning on line 58 in plugins/core/jetbrains-community/src/contrib/org/intellij/images/editor/impl/jcef/JBCefLocalRequestHandler.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Function "createResource" is never used

Check warning

Code scanning / QDJVMC

Unused symbol Warning

Function "createResource" is never used
val normalisedPath = resourcePath.trim('/')
myResources[normalisedPath] = resourceProvider
return "$myProtocol://$myAuthority/$normalisedPath"
}

override fun getResourceRequestHandler(browser: CefBrowser?,
frame: CefFrame?,
request: CefRequest?,
isNavigation: Boolean,
isDownload: Boolean,
requestInitiator: String?,
disableDefaultHandling: BoolRef?): CefResourceRequestHandler {
return RESOURCE_REQUEST_HANDLER
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.

package com.github.rli.cefschemeremotetest.toolWindow

Check notice on line 3 in plugins/core/jetbrains-community/src/contrib/org/intellij/images/editor/impl/jcef/JBCefStreamResourceHandler.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Package name does not match containing directory

Package directive does not match the file location

Check notice

Code scanning / QDJVMC

Package name does not match containing directory Note

Package directive does not match the file location

import com.intellij.openapi.Disposable
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.Disposer
import org.cef.callback.CefCallback
import org.cef.handler.CefResourceHandler
import org.cef.misc.IntRef
import org.cef.misc.StringRef
import org.cef.network.CefRequest
import org.cef.network.CefResponse
import java.io.IOException
import java.io.InputStream

/**
* A handler for managing custom resource requests in JCEF.
* This class implements the `CefResourceHandler` interface, enabling the customization of resource
* loading from a provided input stream. It supports setting MIME types and headers for responses
* and ensures proper disposal of resources.
*
* @param myStream The input stream from which the resource will be read.
* @param myMimeType The MIME type of the response to be sent to the client.
* @param parent A `Disposable` object to which this handler is registered for automatic disposal.
* @param headers Optional headers that will be included in the response.
*/
open class JBCefStreamResourceHandler(
private val myStream: InputStream,
private val myMimeType: String,
parent: Disposable,
private val headers: Map<String, String> = mapOf(),
) : CefResourceHandler, Disposable {
init {
Disposer.register(parent, this)

Check notice on line 35 in plugins/core/jetbrains-community/src/contrib/org/intellij/images/editor/impl/jcef/JBCefStreamResourceHandler.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Leaking 'this' in constructor

Leaking 'this' in constructor of non-final class JBCefStreamResourceHandler

Check notice

Code scanning / QDJVMC

Leaking 'this' in constructor Note

Leaking 'this' in constructor of non-final class JBCefStreamResourceHandler
}

override fun processRequest(request: CefRequest, callback: CefCallback): Boolean {
callback.Continue()
return true
}

override fun getResponseHeaders(response: CefResponse, responseLength: IntRef, redirectUrl: StringRef) {
response.mimeType = myMimeType
response.status = 200
for (header in headers) {
response.setHeaderByName(header.key, header.value, true /* overwrite */)
}
}

override fun readResponse(dataOut: ByteArray, bytesToRead: Int, bytesRead: IntRef, callback: CefCallback): Boolean {
try {
bytesRead.set(myStream.read(dataOut, 0, bytesToRead))
if (bytesRead.get() != -1) {
return true
}
}
catch (_: IOException) {
callback.cancel()
}
bytesRead.set(0)
Disposer.dispose(this)
return false
}

override fun cancel() {
Disposer.dispose(this)
}

override fun dispose() {
try {
myStream.close()
}
catch (e: IOException) {
Logger.getInstance(JBCefStreamResourceHandler::class.java).warn("Failed to close the stream", e)
}
}
}
Loading