1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
package com.intellij.remoteDev.downloader
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task.Backgroundable
import com.intellij.openapi.project.Project
import com.intellij.openapi.rd.createLifetime
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.NlsContexts
import com.intellij.remoteDev.RemoteDevUtilBundle
import com.intellij.remoteDev.util.UrlUtil
import com.intellij.util.application
import com.intellij.util.fragmentParameters
import com.jetbrains.rd.util.lifetime.Lifetime
import org.jetbrains.annotations.ApiStatus
import java.nio.file.Path
import java.util.concurrent.ConcurrentHashMap
@ApiStatus.Experimental
object CodeWithMeGuestLauncher {
private val LOG = logger<CodeWithMeGuestLauncher>()
private val alreadyDownloading = ConcurrentHashMap.newKeySet<String>()
fun downloadCompatibleClientAndLaunch(project: Project?, url: String, @NlsContexts.DialogTitle product: String, onDone: (Lifetime) -> Unit) {
if (!application.isDispatchThread) {
// starting a task from background will call invokeLater, but with wrong modality, so do it ourselves
application.invokeLater({ downloadCompatibleClientAndLaunch(project, url, product, onDone) }, ModalityState.any())
return
}
val uri = UrlUtil.parseOrShowError(url, product) ?: return
if (!alreadyDownloading.add(url)) {
LOG.info("Already downloading a client for $url")
return
}
ProgressManager.getInstance().run(object : Backgroundable(project, RemoteDevUtilBundle.message("launcher.title"), true) {
private var clientLifetime : Lifetime = Lifetime.Terminated
override fun run(progressIndicator: ProgressIndicator) {
try {
val sessionInfo = when (uri.scheme) {
"tcp", "gwws" -> {
val clientBuild = uri.fragmentParameters["cb"] ?: error("there is no client build in url")
val jreBuild = uri.fragmentParameters["jb"] ?: error("there is no jre build in url")
val unattendedMode = uri.fragmentParameters["jt"] != null
CodeWithMeClientDownloader.createSessionInfo(clientBuild, jreBuild, unattendedMode)
}
"http", "https" -> {
progressIndicator.text = RemoteDevUtilBundle.message("launcher.get.client.info")
ThinClientSessionInfoFetcher.getSessionUrl(uri)
}
else -> {
error("scheme '${uri.scheme} is not supported'")
}
}
val pair = CodeWithMeClientDownloader.downloadClientAndJdk(sessionInfo, progressIndicator)
if (pair == null) return
clientLifetime = runDownloadedClient(
lifetime = project?.createLifetime() ?: Lifetime.Eternal,
pathToClient = pair.first,
pathToJre = pair.second,
urlForThinClient = url,
product = product,
progressIndicator = progressIndicator
)
}
catch (t: Throwable) {
LOG.warn(t)
application.invokeLater({
Messages.showErrorDialog(
RemoteDevUtilBundle.message("error.url.issue", t.message ?: "Unknown"),
product)
}, ModalityState.any())
}
finally {
alreadyDownloading.remove(url)
}
}
override fun onSuccess() = onDone.invoke(clientLifetime)
override fun onCancel() = Unit
})
}
fun runDownloadedClient(lifetime: Lifetime, pathToClient: Path, pathToJre: Path, urlForThinClient: String,
@NlsContexts.DialogTitle product: String, progressIndicator: ProgressIndicator?): Lifetime {
// todo: offer to connect as-is?
try {
progressIndicator?.text = RemoteDevUtilBundle.message("launcher.launch.client")
progressIndicator?.text2 = pathToClient.toString()
val thinClientLifetime = CodeWithMeClientDownloader.runCwmGuestProcessFromDownload(lifetime, urlForThinClient, pathToClient, pathToJre)
// Wait a bit until process will be launched and only after that finish task
Thread.sleep(3000)
return thinClientLifetime
}
catch (t: Throwable) {
Logger.getInstance(javaClass).warn(t)
application.invokeLater {
Messages.showErrorDialog(
RemoteDevUtilBundle.message("error.guest.run.issue", t.message ?: "Unknown"),
product)
}
return Lifetime.Terminated
}
}
}
|