Add phoenix-cli script to the JVM distribution (#8)

* Add phoenix-cli script to the JVM distribution

* Close http client after use (otherwise it hangs on the JVM)
This commit is contained in:
Fabrice Drouin 2024-03-26 16:37:25 +01:00 committed by GitHub
parent 0e9b0d6fe4
commit 3fc693e722
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 52 deletions

View File

@ -1,6 +1,5 @@
import Versions.ktor import Versions.ktor
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests
import org.jetbrains.kotlin.ir.util.dumpKotlinLike
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
buildscript { buildscript {
@ -197,6 +196,17 @@ application {
mainClass = "fr.acinq.lightning.bin.MainKt" mainClass = "fr.acinq.lightning.bin.MainKt"
} }
val cliScripts by tasks.register("cliScripts", CreateStartScripts::class) {
mainClass.set("fr.acinq.lightning.cli.PhoenixCliKt")
outputDir = tasks.startScripts.get().outputDir
classpath = tasks.startScripts.get().classpath
applicationName = "phoenix-cli"
}
tasks.startScripts {
dependsOn(cliScripts)
}
distributions { distributions {
main { main {
distributionBaseName = "phoenix" distributionBaseName = "phoenix"

View File

@ -28,8 +28,10 @@ import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.* import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.util.* import io.ktor.server.util.*
import io.ktor.util.* import io.ktor.util.*
import io.ktor.utils.io.core.*
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlin.use
fun main(args: Array<String>) = fun main(args: Array<String>) =
PhoenixCli() PhoenixCli()
@ -97,44 +99,44 @@ abstract class PhoenixCliCommand(val name: String, val help: String, printHelpOn
} }
class GetInfo : PhoenixCliCommand(name = "getinfo", help = "Show basic info about your node") { class GetInfo : PhoenixCliCommand(name = "getinfo", help = "Show basic info about your node") {
override suspend fun httpRequest() = commonOptions.httpClient.get( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = commonOptions.baseUrl / "getinfo" it.get(url = commonOptions.baseUrl / "getinfo")
) }
} }
class GetBalance : PhoenixCliCommand(name = "getbalance", help = "Returns your current balance") { class GetBalance : PhoenixCliCommand(name = "getbalance", help = "Returns your current balance") {
override suspend fun httpRequest() = commonOptions.httpClient.get( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = commonOptions.baseUrl / "getbalance" it.get(url = commonOptions.baseUrl / "getbalance")
) }
} }
class ListChannels : PhoenixCliCommand(name = "listchannels", help = "List all channels") { class ListChannels : PhoenixCliCommand(name = "listchannels", help = "List all channels") {
override suspend fun httpRequest() = commonOptions.httpClient.get( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = commonOptions.baseUrl / "listchannels" it.get(url = commonOptions.baseUrl / "listchannels")
) }
} }
class GetOutgoingPayment : PhoenixCliCommand(name = "getoutgoingpayment", help = "Get outgoing payment") { class GetOutgoingPayment : PhoenixCliCommand(name = "getoutgoingpayment", help = "Get outgoing payment") {
private val uuid by option("--uuid").convert { UUID.fromString(it) }.required() private val uuid by option("--uuid").convert { UUID.fromString(it) }.required()
override suspend fun httpRequest() = commonOptions.httpClient.get( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = commonOptions.baseUrl / "payments/outgoing/$uuid" it.get(url = commonOptions.baseUrl / "payments/outgoing/$uuid")
) }
} }
class GetIncomingPayment : PhoenixCliCommand(name = "getincomingpayment", help = "Get incoming payment") { class GetIncomingPayment : PhoenixCliCommand(name = "getincomingpayment", help = "Get incoming payment") {
private val paymentHash by option("--paymentHash", "--h").convert { ByteVector32.fromValidHex(it) }.required() private val paymentHash by option("--paymentHash", "--h").convert { ByteVector32.fromValidHex(it) }.required()
override suspend fun httpRequest() = commonOptions.httpClient.get( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = commonOptions.baseUrl / "payments/incoming/$paymentHash" it.get(url = commonOptions.baseUrl / "payments/incoming/$paymentHash")
) }
} }
class ListIncomingPayments : PhoenixCliCommand(name = "listincomingpayments", help = "List incoming payments matching the given externalId") { class ListIncomingPayments : PhoenixCliCommand(name = "listincomingpayments", help = "List incoming payments matching the given externalId") {
private val externalId by option("--externalId", "--eid").required() private val externalId by option("--externalId", "--eid").required()
override suspend fun httpRequest() = commonOptions.httpClient.get( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = commonOptions.baseUrl / "payments/incoming", it.get(url = commonOptions.baseUrl / "payments/incoming") {
) { url {
url { parameters.append("externalId", externalId)
parameters.append("externalId", externalId) }
} }
} }
} }
@ -143,54 +145,62 @@ class CreateInvoice : PhoenixCliCommand(name = "createinvoice", help = "Create a
private val amountSat by option("--amountSat").long() private val amountSat by option("--amountSat").long()
private val description by option("--description", "--desc").required() private val description by option("--description", "--desc").required()
private val externalId by option("--externalId") private val externalId by option("--externalId")
override suspend fun httpRequest() = commonOptions.httpClient.submitForm( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = (commonOptions.baseUrl / "createinvoice").toString(), it.submitForm(
formParameters = parameters { url = (commonOptions.baseUrl / "createinvoice").toString(),
amountSat?.let { append("amountSat", it.toString()) } formParameters = parameters {
externalId?.let { append("externalId", it) } amountSat?.let { append("amountSat", it.toString()) }
append("description", description) externalId?.let { append("externalId", it) }
} append("description", description)
) }
)
}
} }
class PayInvoice : PhoenixCliCommand(name = "payinvoice", help = "Pay a Lightning invoice", printHelpOnEmptyArgs = true) { class PayInvoice : PhoenixCliCommand(name = "payinvoice", help = "Pay a Lightning invoice", printHelpOnEmptyArgs = true) {
private val amountSat by option("--amountSat").long() private val amountSat by option("--amountSat").long()
private val invoice by option("--invoice").required().check { Bolt11Invoice.read(it).isSuccess } private val invoice by option("--invoice").required().check { Bolt11Invoice.read(it).isSuccess }
override suspend fun httpRequest() = commonOptions.httpClient.submitForm( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = (commonOptions.baseUrl / "payinvoice").toString(), it.submitForm(
formParameters = parameters { url = (commonOptions.baseUrl / "payinvoice").toString(),
amountSat?.let { append("amountSat", amountSat.toString()) } formParameters = parameters {
append("invoice", invoice) amountSat?.let { append("amountSat", amountSat.toString()) }
} append("invoice", invoice)
) }
)
}
} }
class SendToAddress : PhoenixCliCommand(name = "sendtoaddress", help = "Send to a Bitcoin address", printHelpOnEmptyArgs = true) { class SendToAddress : PhoenixCliCommand(name = "sendtoaddress", help = "Send to a Bitcoin address", printHelpOnEmptyArgs = true) {
private val amountSat by option("--amountSat").long().required() private val amountSat by option("--amountSat").long().required()
private val address by option("--address").required().check { runCatching { Base58Check.decode(it) }.isSuccess || runCatching { Bech32.decodeWitnessAddress(it) }.isSuccess } private val address by option("--address").required().check { runCatching { Base58Check.decode(it) }.isSuccess || runCatching { Bech32.decodeWitnessAddress(it) }.isSuccess }
private val feerateSatByte by option("--feerateSatByte").int().required() private val feerateSatByte by option("--feerateSatByte").int().required()
override suspend fun httpRequest() = commonOptions.httpClient.submitForm( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = (commonOptions.baseUrl / "sendtoaddress").toString(), it.submitForm(
formParameters = parameters { url = (commonOptions.baseUrl / "sendtoaddress").toString(),
append("amountSat", amountSat.toString()) formParameters = parameters {
append("address", address) append("amountSat", amountSat.toString())
append("feerateSatByte", feerateSatByte.toString()) append("address", address)
} append("feerateSatByte", feerateSatByte.toString())
) }
)
}
} }
class CloseChannel : PhoenixCliCommand(name = "closechannel", help = "Close channel", printHelpOnEmptyArgs = true) { class CloseChannel : PhoenixCliCommand(name = "closechannel", help = "Close channel", printHelpOnEmptyArgs = true) {
private val channelId by option("--channelId").convert { ByteVector32.fromValidHex(it) }.required() private val channelId by option("--channelId").convert { ByteVector32.fromValidHex(it) }.required()
private val address by option("--address").required().check { runCatching { Base58Check.decode(it) }.isSuccess || runCatching { Bech32.decodeWitnessAddress(it) }.isSuccess } private val address by option("--address").required().check { runCatching { Base58Check.decode(it) }.isSuccess || runCatching { Bech32.decodeWitnessAddress(it) }.isSuccess }
private val feerateSatByte by option("--feerateSatByte").int().required() private val feerateSatByte by option("--feerateSatByte").int().required()
override suspend fun httpRequest() = commonOptions.httpClient.submitForm( override suspend fun httpRequest() = commonOptions.httpClient.use {
url = (commonOptions.baseUrl / "closechannel").toString(), it.submitForm(
formParameters = parameters { url = (commonOptions.baseUrl / "closechannel").toString(),
append("channelId", channelId.toHex()) formParameters = parameters {
append("address", address) append("channelId", channelId.toHex())
append("feerateSatByte", feerateSatByte.toString()) append("address", address)
} append("feerateSatByte", feerateSatByte.toString())
) }
)
}
} }
operator fun Url.div(path: String) = Url(URLBuilder(this).appendPathSegments(path)) operator fun Url.div(path: String) = Url(URLBuilder(this).appendPathSegments(path))