From 683afdb56919d337ccb27918c67954b955697f20 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 22 Oct 2015 04:57:27 -0700 Subject: [PATCH] Refactor commands. --- .../internal/remote/GetDependenciesCommand.kt | 25 ++++++------- .../kobalt/internal/remote/KobaltClient.kt | 6 +-- .../kobalt/internal/remote/KobaltServer.kt | 37 +++++++++++++++++-- .../kobalt/internal/remote/PingCommand.kt | 13 ++++++- 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt index ba61eaf4..76bf886d 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt @@ -55,21 +55,18 @@ class GetDependenciesCommand @Inject constructor(val executors: KobaltExecutors, projects.add(ProjectData(project.name!!, allDependencies)) } log(1, "Returning BuildScriptInfo") - val result = Gson().toJson(GetDependenciesData(projects).toData()) + val result = toCommandDataJson(Gson().toJson(GetDependenciesData(projects))) log(2, " $result") return result } + + ///// + // The JSON payloads that this command uses + // + + class DependencyData(val id: String, val scope: String, val path: String) + + class ProjectData( val name: String, val dependencies: List) + + class GetDependenciesData(val projects: List) } - -class DependencyData(val id: String, val scope: String, val path: String) - -class ProjectData( val name: String, val dependencies: List) - -class GetDependenciesData(val projects: List) { - fun toData() : CommandData { - val data = Gson().toJson(this) - return CommandData("getDependencies", data) - } -} - - diff --git a/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltClient.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltClient.kt index cf9935e9..9d1ce831 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltClient.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltClient.kt @@ -47,7 +47,7 @@ public class KobaltClient @Inject constructor() : Runnable { done = true } else { val data = jo.get("data").asString - val dd = Gson().fromJson(data, GetDependenciesData::class.java) + val dd = Gson().fromJson(data, GetDependenciesCommand.GetDependenciesData::class.java) println("Read GetDependencyData, project count: ${dd.projects.size()}") line = ins.readLine() } @@ -59,8 +59,4 @@ public class KobaltClient @Inject constructor() : Runnable { } } } - - fun sendInfo(info: BuildFileCompiler.BuildScriptInfo) { - outgoing!!.println("Sending info with project count: " + info.projects.size()) - } } diff --git a/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltServer.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltServer.kt index 3b90e45c..2fc7d93e 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltServer.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltServer.kt @@ -3,6 +3,7 @@ package com.beust.kobalt.internal.remote import com.beust.kobalt.Args import com.beust.kobalt.api.Kobalt import com.beust.kobalt.misc.log +import com.google.gson.Gson import com.google.gson.JsonObject import com.google.gson.JsonParser import com.google.inject.Inject @@ -13,15 +14,43 @@ import java.io.PrintWriter import java.net.ServerSocket import java.net.SocketException -interface ICommandSender { - fun sendData(content: String) -} - +/** + * All commands implement this interface. + */ interface ICommand { + /** + * The name of this command. + */ val name: String + + /** + * Run this command based on the information received from the server. When done, use + * the sender object to send back a response. + */ fun run(sender: ICommandSender, received: JsonObject) + + fun toCommandDataJson(data: String) = Gson().toJson(CommandData(name, data)) } +/** + * Passed to a command in its `run` method so it can send information back to the caller. + * @param The string content that will be sent in the "data" field. + */ +interface ICommandSender { + fun sendData(data: String) +} + +/** + * The JSON payload that commands exchange follow the following pattern: + * { + * name: "nameOfTheCommand" + * data: a JSON string containing the payload itself + * } + * This allows commands to be tested for their name first, after which each command can + * decode its own specific payload by parsing the JSON in the "data" field and mapping + * it into a Kotlin *Data class. The downside of this approach is a double parsing, + * but since the data part is parsed as a string first, this is probably not a huge deal. + */ class CommandData(val commandName: String, val data: String) @Singleton diff --git a/src/main/kotlin/com/beust/kobalt/internal/remote/PingCommand.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/PingCommand.kt index 569b9fe1..d05d1907 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/remote/PingCommand.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/PingCommand.kt @@ -1,5 +1,7 @@ package com.beust.kobalt.internal.remote +import com.beust.kobalt.misc.log +import com.google.gson.Gson import com.google.gson.JsonObject /** @@ -12,7 +14,14 @@ import com.google.gson.JsonObject */ class PingCommand() : ICommand { override val name = "ping" - override fun run(sender: ICommandSender, received: JsonObject) = - sender.sendData("{ \"response\" : \"${received.toString()}\"" + " }") + + override fun run(sender: ICommandSender, received: JsonObject) { + val commandData = toCommandDataJson(Gson().toJson(PingData(received.toString()))) + val result = Gson().toJson(commandData) + log(1, "ping returning: $result") + sender.sendData(result) + } + + class PingData(val received: String) }