mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-26 08:27:12 -07:00
First version of the WebSocket server.
This commit is contained in:
parent
c52da23354
commit
f1e75223a3
4 changed files with 149 additions and 7 deletions
|
@ -1,8 +1,7 @@
|
|||
|
||||
import com.beust.kobalt.TaskResult
|
||||
import com.beust.kobalt.api.License
|
||||
import com.beust.kobalt.api.Project
|
||||
import com.beust.kobalt.api.Scm
|
||||
import com.beust.kobalt.*
|
||||
import com.beust.kobalt.api.*
|
||||
import com.beust.kobalt.api.annotation.Task
|
||||
import com.beust.kobalt.homeDir
|
||||
import com.beust.kobalt.plugin.application.application
|
||||
|
@ -137,6 +136,7 @@ val kobaltApp = project(kobaltPluginApi, wrapper) {
|
|||
"com.google.code.gson:gson:${Versions.gson}",
|
||||
"com.squareup.retrofit2:retrofit:${Versions.retrofit}",
|
||||
"com.squareup.retrofit2:converter-gson:${Versions.retrofit}",
|
||||
"com.squareup.okhttp3:okhttp-ws:${Versions.okhttp}",
|
||||
"org.codehaus.plexus:plexus-utils:3.0.22",
|
||||
"biz.aQute.bnd:bndlib:2.4.0",
|
||||
|
||||
|
|
|
@ -16,10 +16,15 @@ import com.google.inject.Inject
|
|||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
|
||||
interface IProgressListener {
|
||||
fun onProgress(progress: Int? = null, message: String? = null)
|
||||
}
|
||||
|
||||
class DependencyData @Inject constructor(val executors: KobaltExecutors, val dependencyManager: DependencyManager,
|
||||
val buildFileCompilerFactory: BuildFileCompiler.IFactory, val pluginInfo: PluginInfo,
|
||||
val taskManager: TaskManager) {
|
||||
fun dependenciesDataFor(buildFilePath: String, args: Args) : GetDependenciesData {
|
||||
fun dependenciesDataFor(buildFilePath: String, args: Args, progressListener: IProgressListener? = null)
|
||||
: GetDependenciesData {
|
||||
val projectDatas = arrayListOf<ProjectData>()
|
||||
|
||||
fun toDependencyData(d: IClasspathDependency, scope: String): DependencyData {
|
||||
|
@ -38,7 +43,10 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
|
|||
}
|
||||
|
||||
val allTasks = hashSetOf<TaskData>()
|
||||
projectResult.projects.forEach { project ->
|
||||
projectResult.projects.withIndex().forEach { wi ->
|
||||
val project = wi.value
|
||||
progressListener?.onProgress(message = "Synchronizing project ${project.name} "
|
||||
+ (wi.index + 1) + "/" + projectResult.projects.size)
|
||||
val compileDependencies = pluginDependencies.map { toDependencyData(it, "compile") } +
|
||||
allDeps(project.compileDependencies).map { toDependencyData(it, "compile") } +
|
||||
allDeps(project.compileProvidedDependencies).map { toDependencyData(it, "compile") }
|
||||
|
@ -88,5 +96,9 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
|
|||
|
||||
class GetDependenciesData(val projects: List<ProjectData> = emptyList(),
|
||||
val allTasks: Collection<TaskData> = emptySet(),
|
||||
val errorMessage: String?)
|
||||
val errorMessage: String?) {
|
||||
companion object {
|
||||
val NAME = "GetDependencies"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.beust.kobalt.app.remote
|
||||
|
||||
import com.beust.kobalt.Args
|
||||
import com.beust.kobalt.KobaltException
|
||||
import com.beust.kobalt.SystemProperties
|
||||
import com.beust.kobalt.api.Kobalt
|
||||
import com.beust.kobalt.app.MainModule
|
||||
|
@ -9,11 +10,19 @@ import com.beust.kobalt.internal.KobaltSettings
|
|||
import com.beust.kobalt.misc.KFiles
|
||||
import com.beust.kobalt.misc.log
|
||||
import com.beust.kobalt.misc.warn
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.google.inject.Guice
|
||||
import com.google.inject.Inject
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.ResponseBody
|
||||
import okhttp3.ws.WebSocket
|
||||
import okhttp3.ws.WebSocketCall
|
||||
import okhttp3.ws.WebSocketListener
|
||||
import okio.Buffer
|
||||
import retrofit2.Call
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
@ -28,7 +37,7 @@ import java.util.concurrent.Executors
|
|||
|
||||
fun main(argv: Array<String>) {
|
||||
Kobalt.INJECTOR = Guice.createInjector(MainModule(Args(), KobaltSettings.readSettingsXml()))
|
||||
KobaltClient().run()
|
||||
KobaltWebSocketClient().run()
|
||||
}
|
||||
|
||||
interface Api {
|
||||
|
@ -39,6 +48,53 @@ interface Api {
|
|||
fun getDependencies(@Query("buildFile") buildFile: String) : Call<List<DependencyData.GetDependenciesData>>
|
||||
}
|
||||
|
||||
class KobaltWebSocketClient : Runnable {
|
||||
override fun run() {
|
||||
val client = OkHttpClient()
|
||||
val request = Request.Builder()
|
||||
// .url("ws://echo.websocket.org")
|
||||
.url("ws://localhost:1234/v1/getDependencies?buildFile=/Users/beust/kotlin/kobalt/kobalt/src/Build.kt")
|
||||
.build()
|
||||
var webSocket: WebSocket? = null
|
||||
val ws = WebSocketCall.create(client, request).enqueue(object: WebSocketListener {
|
||||
override fun onOpen(ws: WebSocket, response: Response) {
|
||||
webSocket = ws
|
||||
}
|
||||
|
||||
override fun onPong(p0: Buffer?) {
|
||||
println("WebSocket pong")
|
||||
}
|
||||
|
||||
override fun onClose(p0: Int, p1: String?) {
|
||||
println("WebSocket closed")
|
||||
}
|
||||
|
||||
override fun onFailure(ex: IOException, response: Response?) {
|
||||
ex.printStackTrace()
|
||||
error("WebSocket failure: ${ex.message} response: $response")
|
||||
}
|
||||
|
||||
override fun onMessage(body: ResponseBody) {
|
||||
val json = body.string()
|
||||
val wsCommand = Gson().fromJson(json, WebSocketCommand::class.java)
|
||||
if (wsCommand.errorMessage != null) {
|
||||
warn("Received error message from server: " + wsCommand.errorMessage)
|
||||
} else {
|
||||
if (wsCommand.commandName == DependencyData.GetDependenciesData.NAME) {
|
||||
val dd = Gson().fromJson(wsCommand.payload, DependencyData.GetDependenciesData::class.java)
|
||||
println("Received dependency data: " + dd.projects.size + " projects")
|
||||
} else if (wsCommand.commandName == ProgressCommand.NAME) {
|
||||
val progress = Gson().fromJson(wsCommand.payload, ProgressCommand::class.java)
|
||||
println(progress.message + (progress.progress ?: ""))
|
||||
} else {
|
||||
throw KobaltException("Unknown command: ${wsCommand.commandName} json:\n$json")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class KobaltClient : Runnable {
|
||||
var outgoing: PrintWriter? = null
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ import com.beust.kobalt.app.Templates
|
|||
import com.beust.kobalt.internal.PluginInfo
|
||||
import com.google.common.collect.ListMultimap
|
||||
import com.google.gson.Gson
|
||||
import org.eclipse.jetty.websocket.api.RemoteEndpoint
|
||||
import org.eclipse.jetty.websocket.api.Session
|
||||
import org.eclipse.jetty.websocket.api.WebSocketListener
|
||||
import spark.ResponseTransformer
|
||||
import spark.Route
|
||||
import spark.Spark
|
||||
|
@ -34,8 +37,12 @@ class SparkServer(val initCallback: (String) -> List<Project>, val cleanUpCallba
|
|||
private fun jsonRoute(path: String, route: Route)
|
||||
= Spark.get(path, "application/json", route, JsonTransformer())
|
||||
|
||||
val log = org.slf4j.LoggerFactory.getLogger("SparkServer")
|
||||
|
||||
override fun run(port: Int) {
|
||||
log.debug("RUNNING")
|
||||
Spark.port(port)
|
||||
Spark.webSocket("/v1/getDependencies", GetDependenciesChatHandler::class.java)
|
||||
Spark.get("/ping", { req, res -> """ { "result" : "ok" } """ })
|
||||
Spark.get("/quit", { req, res ->
|
||||
Executors.newFixedThreadPool(1).let { executor ->
|
||||
|
@ -72,9 +79,76 @@ class SparkServer(val initCallback: (String) -> List<Project>, val cleanUpCallba
|
|||
jsonRoute("/v0/getTemplates", Route { request, response ->
|
||||
TemplatesData.create(Templates().getTemplates(pluginInfo))
|
||||
})
|
||||
Spark.init()
|
||||
}
|
||||
}
|
||||
|
||||
class GetDependenciesChatHandler : WebSocketListener {
|
||||
var session: Session? = null
|
||||
|
||||
override fun onWebSocketClose(code: Int, reason: String?) {
|
||||
println("ON CLOSE $code reason: $reason")
|
||||
}
|
||||
|
||||
override fun onWebSocketError(cause: Throwable?) {
|
||||
cause?.printStackTrace()
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
fun <T> sendWebsocketCommand(endpoint: RemoteEndpoint, commandName: String, payload: T) {
|
||||
endpoint.sendString(Gson().toJson(WebSocketCommand(commandName, payload = Gson().toJson(payload))))
|
||||
}
|
||||
|
||||
override fun onWebSocketConnect(s: Session) {
|
||||
session = s
|
||||
val buildFileParams = s.upgradeRequest.parameterMap["buildFile"]
|
||||
if (buildFileParams != null) {
|
||||
val buildFile = buildFileParams[0]
|
||||
|
||||
val result = if (buildFile != null) {
|
||||
try {
|
||||
val dependencyData = Kobalt.INJECTOR.getInstance(DependencyData::class.java)
|
||||
val args = Kobalt.INJECTOR.getInstance(Args::class.java)
|
||||
|
||||
dependencyData.dependenciesDataFor(buildFile, args, object : IProgressListener {
|
||||
override fun onProgress(progress: Int?, message: String?) {
|
||||
sendWebsocketCommand(s.remote, ProgressCommand.NAME, ProgressCommand(progress, message))
|
||||
}
|
||||
})
|
||||
} catch(ex: Exception) {
|
||||
DependencyData.GetDependenciesData(errorMessage = ex.message)
|
||||
} finally {
|
||||
SparkServer.cleanUpCallback()
|
||||
}
|
||||
} else {
|
||||
DependencyData.GetDependenciesData(
|
||||
errorMessage = "buildFile wasn't passed in the query parameter")
|
||||
}
|
||||
println("GOT DEPENDENCY DATA: $result")
|
||||
sendWebsocketCommand(s.remote, DependencyData.GetDependenciesData.NAME, result)
|
||||
s.close()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onWebSocketText(message: String?) {
|
||||
println("RECEIVED TEXT: $message")
|
||||
session?.remote?.sendString("Response: $message")
|
||||
}
|
||||
|
||||
override fun onWebSocketBinary(payload: ByteArray?, offset: Int, len: Int) {
|
||||
println("RECEIVED BINARY: $payload")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ProgressCommand(val progress: Int? = null, val message: String? = null) {
|
||||
companion object {
|
||||
val NAME = "ProgressCommand"
|
||||
}
|
||||
}
|
||||
|
||||
class WebSocketCommand(val commandName: String, val errorMessage: String? = null, val payload: String)
|
||||
|
||||
class TemplateData(val pluginName: String, val templates: List<String>)
|
||||
|
||||
class TemplatesData(val templates: List<TemplateData>) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue