Skip to content

Commit f2dc464

Browse files
authored
Support for toolbox 2.6.0.38311 (#8)
- fixes login screen and glitches related jumping to the workspaces page once the connection to Coder deployment is estabilished. - support for opening URLs in browser - fixes user agent reporting - fixes connection status rendering - a couple of functions on the existing models and views transformed into class properties - while other functions are now suspend functions - upgrade kotlin dependencies because Toolbox 2.6.0.38311 runs with Kotlin stdlib 2.1.0 therefore I've upgraded the Kotlin compiler to match the runtime. - similarly coroutines, serialization and KSP support had to be upgraded.
1 parent 7f9e1b3 commit f2dc464

20 files changed

+365
-111
lines changed

build.gradle.kts

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ jvmWrapper {
3939
dependencies {
4040
compileOnly(libs.bundles.toolbox.plugin.api)
4141
implementation(libs.slf4j)
42-
implementation(libs.tinylog)
4342
implementation(libs.bundles.serialization)
4443
implementation(libs.coroutines.core)
4544
implementation(libs.okhttp)

gradle/libs.versions.toml

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
[versions]
2-
toolbox-plugin-api = "0.6.2.6.0.37447"
3-
kotlin = "2.0.10"
4-
coroutines = "1.7.3"
5-
serialization = "1.5.0"
2+
toolbox-plugin-api = "0.7.2.6.0.38311"
3+
kotlin = "2.1.0"
4+
coroutines = "1.10.1"
5+
serialization = "1.8.0"
66
okhttp = "4.10.0"
77
slf4j = "2.0.3"
8-
tinylog = "2.7.0"
98
dependency-license-report = "2.5"
109
marketplace-client = "2.0.38"
1110
gradle-wrapper = "0.14.0"
1211
exec = "1.12"
1312
moshi = "1.15.1"
14-
ksp = "2.0.10-1.0.24"
13+
ksp = "2.1.0-1.0.29"
1514
retrofit = "2.8.2"
1615

1716
[libraries]
@@ -24,7 +23,6 @@ serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-jso
2423
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "serialization" }
2524
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
2625
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
27-
tinylog = {module = "org.tinylog:slf4j-tinylog", version.ref = "tinylog"}
2826
exec = { module = "org.zeroturnaround:zt-exec", version.ref = "exec" }
2927
moshi = { module = "com.squareup.moshi:moshi", version.ref = "moshi"}
3028
moshi-codegen = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "moshi"}

src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt

+8-10
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import com.jetbrains.toolbox.api.remoteDev.states.EnvironmentStateConsumer
1616
import com.jetbrains.toolbox.api.ui.ToolboxUi
1717
import kotlinx.coroutines.CoroutineScope
1818
import kotlinx.coroutines.launch
19-
import java.util.concurrent.CompletableFuture
2019

2120
/**
2221
* Represents an agent and workspace combination.
@@ -29,12 +28,12 @@ class CoderRemoteEnvironment(
2928
private var workspace: Workspace,
3029
private var agent: WorkspaceAgent,
3130
private var cs: CoroutineScope,
32-
) : AbstractRemoteProviderEnvironment() {
31+
) : AbstractRemoteProviderEnvironment("${workspace.name}.${agent.name}") {
3332
private var status = WorkspaceAndAgentStatus.from(workspace, agent)
3433

3534
private val ui: ToolboxUi = serviceLocator.getService(ToolboxUi::class.java)
36-
override fun getId(): String = "${workspace.name}.${agent.name}"
37-
override fun getName(): String = "${workspace.name}.${agent.name}"
35+
36+
override var name: String = "${workspace.name}.${agent.name}"
3837

3938
init {
4039
actionsList.add(
@@ -105,12 +104,11 @@ class CoderRemoteEnvironment(
105104
* The contents are provided by the SSH view provided by Toolbox, all we
106105
* have to do is provide it a host name.
107106
*/
108-
override fun getContentsView(): CompletableFuture<EnvironmentContentsView> =
109-
CompletableFuture.completedFuture(EnvironmentView(client.url, workspace, agent))
107+
override suspend fun getContentsView(): EnvironmentContentsView = EnvironmentView(client.url, workspace, agent)
110108

111109
/**
112-
* Does nothing. In theory we could do something like start the workspace
113-
* when you click into the workspace but you would still need to press
110+
* Does nothing. In theory, we could do something like start the workspace
111+
* when you click into the workspace, but you would still need to press
114112
* "connect" anyway before the content is populated so there does not seem
115113
* to be much value.
116114
*/
@@ -140,12 +138,12 @@ class CoderRemoteEnvironment(
140138
if (other == null) return false
141139
if (this === other) return true // Note the triple ===
142140
if (other !is CoderRemoteEnvironment) return false
143-
if (getId() != other.getId()) return false
141+
if (id != other.id) return false
144142
return true
145143
}
146144

147145
/**
148146
* Companion to equals, for sets.
149147
*/
150-
override fun hashCode(): Int = getId().hashCode()
148+
override fun hashCode(): Int = id.hashCode()
151149
}

src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt

+15-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.coder.toolbox
22

33
import com.coder.toolbox.cli.CoderCLIManager
4+
import com.coder.toolbox.logger.CoderLoggerFactory
45
import com.coder.toolbox.sdk.CoderRestClient
56
import com.coder.toolbox.sdk.v2.models.WorkspaceStatus
67
import com.coder.toolbox.services.CoderSecretsService
@@ -34,7 +35,6 @@ import kotlinx.coroutines.delay
3435
import kotlinx.coroutines.isActive
3536
import kotlinx.coroutines.launch
3637
import okhttp3.OkHttpClient
37-
import org.slf4j.LoggerFactory
3838
import java.net.URI
3939
import java.net.URL
4040
import kotlin.coroutines.cancellation.CancellationException
@@ -43,8 +43,8 @@ import kotlin.time.Duration.Companion.seconds
4343
class CoderRemoteProvider(
4444
private val serviceLocator: ServiceLocator,
4545
private val httpClient: OkHttpClient,
46-
) : RemoteProvider {
47-
private val logger = LoggerFactory.getLogger(javaClass)
46+
) : RemoteProvider("Coder") {
47+
private val logger = CoderLoggerFactory.getLogger(javaClass)
4848

4949
private val ui: ToolboxUi = serviceLocator.getService(ToolboxUi::class.java)
5050
private val consumer: RemoteEnvironmentConsumer = serviceLocator.getService(RemoteEnvironmentConsumer::class.java)
@@ -185,18 +185,18 @@ class CoderRemoteProvider(
185185
consumer.consumeEnvironments(emptyList(), true)
186186
}
187187

188-
override fun getName(): String = "Coder"
189-
override fun getSvgIcon(): SvgIcon =
188+
override val svgIcon: SvgIcon =
190189
SvgIcon(this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf())
191190

192-
override fun getNoEnvironmentsSvgIcon(): ByteArray =
193-
this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf()
191+
override val noEnvironmentsSvgIcon: SvgIcon? =
192+
SvgIcon(this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf())
194193

195194
/**
196195
* TODO@JB: It would be nice to show "loading workspaces" at first but it
197196
* appears to be only called once.
198197
*/
199-
override fun getNoEnvironmentsDescription(): String = "No workspaces yet"
198+
override val noEnvironmentsDescription: String? = "No workspaces yet"
199+
200200

201201
/**
202202
* TODO@JB: Supposedly, setting this to false causes the new environment
@@ -205,7 +205,7 @@ class CoderRemoteProvider(
205205
* this changes it would be nice to have a new spot to show the
206206
* URL.
207207
*/
208-
override fun canCreateNewEnvironments(): Boolean = false
208+
override val canCreateNewEnvironments: Boolean = false
209209

210210
/**
211211
* Just displays the deployment URL at the moment, but we could use this as
@@ -216,7 +216,7 @@ class CoderRemoteProvider(
216216
/**
217217
* We always show a list of environments.
218218
*/
219-
override fun isSingleEnvironment(): Boolean = false
219+
override val isSingleEnvironment: Boolean = false
220220

221221
/**
222222
* TODO: Possibly a good idea to start/stop polling based on visibility, at
@@ -241,9 +241,11 @@ class CoderRemoteProvider(
241241
*/
242242
override fun handleUri(uri: URI) {
243243
val params = uri.toQueryParameters()
244-
val name = linkHandler.handle(params)
245-
// TODO@JB: Now what? How do we actually connect this workspace?
246-
logger.debug("External request for {}: {}", name, uri)
244+
coroutineScope.launch {
245+
val name = linkHandler.handle(params)
246+
// TODO@JB: Now what? How do we actually connect this workspace?
247+
logger.debug("External request for {}: {}", name, uri)
248+
}
247249
}
248250

249251
/**

src/main/kotlin/com/coder/toolbox/CoderToolboxExtension.kt

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.coder.toolbox
22

3+
import com.coder.toolbox.logger.CoderLoggerFactory
34
import com.jetbrains.toolbox.api.core.ServiceLocator
5+
import com.jetbrains.toolbox.api.core.diagnostics.Logger
46
import com.jetbrains.toolbox.api.remoteDev.RemoteDevExtension
57
import com.jetbrains.toolbox.api.remoteDev.RemoteProvider
68
import okhttp3.OkHttpClient
@@ -11,6 +13,9 @@ import okhttp3.OkHttpClient
1113
class CoderToolboxExtension : RemoteDevExtension {
1214
// All services must be passed in here and threaded as necessary.
1315
override fun createRemoteProviderPluginInstance(serviceLocator: ServiceLocator): RemoteProvider {
16+
// initialize logger factory
17+
CoderLoggerFactory.tLogger = serviceLocator.getService(Logger::class.java)
18+
1419
return CoderRemoteProvider(
1520
serviceLocator,
1621
OkHttpClient(),

src/main/kotlin/com/coder/toolbox/browser/BrowserUtil.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import org.zeroturnaround.exec.ProcessExecutor
66

77
class BrowserUtil {
88
companion object {
9-
fun browse(url: String, errorHandler: (BrowserException) -> Unit) {
9+
suspend fun browse(url: String, errorHandler: suspend (BrowserException) -> Unit) {
1010
val os = getOS()
1111
if (os == null) {
1212
errorHandler(BrowserException("Failed to open the URL because we can't detect the OS"))
@@ -19,7 +19,7 @@ class BrowserUtil {
1919
}
2020
}
2121

22-
private fun linuxBrowse(url: String, errorHandler: (BrowserException) -> Unit) {
22+
private suspend fun linuxBrowse(url: String, errorHandler: suspend (BrowserException) -> Unit) {
2323
try {
2424
if (OS.LINUX.getDesktopEnvironment()?.uppercase()?.contains("GNOME") == true) {
2525
exec("gnome-open", url)
@@ -36,15 +36,15 @@ class BrowserUtil {
3636
}
3737
}
3838

39-
private fun macBrowse(url: String, errorHandler: (BrowserException) -> Unit) {
39+
private suspend fun macBrowse(url: String, errorHandler: suspend (BrowserException) -> Unit) {
4040
try {
4141
exec("open", url)
4242
} catch (e: Exception) {
4343
errorHandler(BrowserException("Failed to open URL because an error was encountered.", e))
4444
}
4545
}
4646

47-
private fun windowsBrowse(url: String, errorHandler: (BrowserException) -> Unit) {
47+
private suspend fun windowsBrowse(url: String, errorHandler: suspend (BrowserException) -> Unit) {
4848
try {
4949
exec("cmd", "start \"$url\"")
5050
} catch (e: Exception) {

src/main/kotlin/com/coder/toolbox/cli/CoderCLIManager.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.coder.toolbox.cli
33
import com.coder.toolbox.cli.ex.MissingVersionException
44
import com.coder.toolbox.cli.ex.ResponseException
55
import com.coder.toolbox.cli.ex.SSHConfigFormatException
6+
import com.coder.toolbox.logger.CoderLoggerFactory
67
import com.coder.toolbox.settings.CoderSettings
78
import com.coder.toolbox.settings.CoderSettingsState
89
import com.coder.toolbox.util.CoderHostnameVerifier
@@ -20,7 +21,6 @@ import com.squareup.moshi.Json
2021
import com.squareup.moshi.JsonClass
2122
import com.squareup.moshi.JsonDataException
2223
import com.squareup.moshi.Moshi
23-
import org.slf4j.LoggerFactory
2424
import org.zeroturnaround.exec.ProcessExecutor
2525
import java.io.EOFException
2626
import java.io.FileInputStream
@@ -126,7 +126,7 @@ class CoderCLIManager(
126126
// manager to download to the data directory instead.
127127
forceDownloadToData: Boolean = false,
128128
) {
129-
private val logger = LoggerFactory.getLogger(javaClass)
129+
private val logger = CoderLoggerFactory.getLogger(javaClass)
130130

131131
val remoteBinaryURL: URL = settings.binSource(deploymentURL)
132132
val localBinaryPath: Path = settings.binPath(deploymentURL, forceDownloadToData)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.coder.toolbox.logger
2+
3+
import org.slf4j.ILoggerFactory
4+
import org.slf4j.Logger
5+
import com.jetbrains.toolbox.api.core.diagnostics.Logger as ToolboxLogger
6+
7+
object CoderLoggerFactory : ILoggerFactory {
8+
var tLogger: ToolboxLogger? = null
9+
10+
fun getLogger(clazz: Class<Any>): Logger = getLogger(clazz.name)
11+
override fun getLogger(clazzName: String): Logger = LoggerImpl(clazzName, tLogger)
12+
}

0 commit comments

Comments
 (0)