(cli) Add PhoenixCliCommand class for convenience

This abstract class catches errors and echoes a short message
instead of printing a stacktrace. This is especially useful
when the CLI cannot connect to phoenixd (e.g. wrong port). We
can also factorise some of the code.
This commit is contained in:
Dominique Padiou 2024-03-18 19:33:33 +01:00
parent 4b59be44b5
commit 3d37e0adc7
No known key found for this signature in database
GPG Key ID: 574C8C6A1673E987

View File

@ -79,93 +79,69 @@ class PhoenixCli : CliktCommand() {
} }
} }
class GetInfo : CliktCommand(name = "getinfo", help = "Show basic info about your node") { abstract class PhoenixCliCommand(val name: String, val help: String, printHelpOnEmptyArgs: Boolean = false) : CliktCommand(name = name, help = help, printHelpOnEmptyArgs = printHelpOnEmptyArgs) {
private val commonOptions by requireObject<HttpConf>() internal val commonOptions by requireObject<HttpConf>()
abstract suspend fun httpRequest(): HttpResponse
override fun run() { override fun run() {
runBlocking { runBlocking {
val res = commonOptions.httpClient.get( try {
val res = httpRequest()
echo(res.bodyAsText())
} catch (e: Exception) {
echo("[${this@PhoenixCliCommand.name}] error: ${e.message}")
}
}
}
}
class GetInfo : PhoenixCliCommand(name = "getinfo", help = "Show basic info about your node") {
override suspend fun httpRequest() = commonOptions.httpClient.get(
url = commonOptions.baseUrl / "getinfo" url = commonOptions.baseUrl / "getinfo"
) )
echo(res.bodyAsText())
}
}
} }
class GetBalance : CliktCommand(name = "getbalance", help = "Returns your current balance") { class GetBalance : PhoenixCliCommand(name = "getbalance", help = "Returns your current balance") {
private val commonOptions by requireObject<HttpConf>() override suspend fun httpRequest() = commonOptions.httpClient.get(
override fun run() {
runBlocking {
val res = commonOptions.httpClient.get(
url = commonOptions.baseUrl / "getbalance" url = commonOptions.baseUrl / "getbalance"
) )
echo(res.bodyAsText())
}
}
} }
class ListChannels : CliktCommand(name = "listchannels", help = "List all channels") { class ListChannels : PhoenixCliCommand(name = "listchannels", help = "List all channels") {
private val commonOptions by requireObject<HttpConf>() override suspend fun httpRequest() = commonOptions.httpClient.get(
override fun run() {
runBlocking {
val res = commonOptions.httpClient.get(
url = commonOptions.baseUrl / "listchannels" url = commonOptions.baseUrl / "listchannels"
) )
echo(res.bodyAsText())
}
}
} }
class GetOutgoingPayment : CliktCommand(name = "getoutgoingpayment", help = "Get outgoing payment") { class GetOutgoingPayment : PhoenixCliCommand(name = "getoutgoingpayment", help = "Get outgoing payment") {
private val commonOptions by requireObject<HttpConf>()
private val uuid by option("--uuid").convert { UUID.fromString(it) }.required() private val uuid by option("--uuid").convert { UUID.fromString(it) }.required()
override fun run() { override suspend fun httpRequest() = commonOptions.httpClient.get(
runBlocking {
val res = commonOptions.httpClient.get(
url = commonOptions.baseUrl / "payments/outgoing/$uuid" url = commonOptions.baseUrl / "payments/outgoing/$uuid"
) )
echo(res.bodyAsText())
}
}
} }
class GetIncomingPayment : CliktCommand(name = "getincomingpayment", help = "Get incoming payment") { class GetIncomingPayment : PhoenixCliCommand(name = "getincomingpayment", help = "Get incoming payment") {
private val commonOptions by requireObject<HttpConf>()
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 fun run() { override suspend fun httpRequest() = commonOptions.httpClient.get(
runBlocking {
val res = commonOptions.httpClient.get(
url = commonOptions.baseUrl / "payments/incoming/$paymentHash" url = commonOptions.baseUrl / "payments/incoming/$paymentHash"
) )
echo(res.bodyAsText())
}
}
} }
class ListIncomingPayments : CliktCommand(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 commonOptions by requireObject<HttpConf>()
private val externalId by option("--externalId", "--eid").required() private val externalId by option("--externalId", "--eid").required()
override fun run() { override suspend fun httpRequest() = commonOptions.httpClient.get(
runBlocking {
val res = commonOptions.httpClient.get(
url = commonOptions.baseUrl / "payments/incoming", url = commonOptions.baseUrl / "payments/incoming",
) { ) {
url { url {
parameters.append("externalId", externalId) parameters.append("externalId", externalId)
} }
} }
echo(res.bodyAsText())
}
}
} }
class CreateInvoice : CliktCommand(name = "createinvoice", help = "Create a Lightning invoice", printHelpOnEmptyArgs = true) { class CreateInvoice : PhoenixCliCommand(name = "createinvoice", help = "Create a Lightning invoice", printHelpOnEmptyArgs = true) {
private val commonOptions by requireObject<HttpConf>()
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 fun run() { override suspend fun httpRequest() = commonOptions.httpClient.submitForm(
runBlocking {
val res = commonOptions.httpClient.submitForm(
url = (commonOptions.baseUrl / "createinvoice").toString(), url = (commonOptions.baseUrl / "createinvoice").toString(),
formParameters = parameters { formParameters = parameters {
amountSat?.let { append("amountSat", it.toString()) } amountSat?.let { append("amountSat", it.toString()) }
@ -173,37 +149,25 @@ class CreateInvoice : CliktCommand(name = "createinvoice", help = "Create a Ligh
append("description", description) append("description", description)
} }
) )
echo(res.bodyAsText())
}
}
} }
class PayInvoice : CliktCommand(name = "payinvoice", help = "Pay a Lightning invoice", printHelpOnEmptyArgs = true) { class PayInvoice : PhoenixCliCommand(name = "payinvoice", help = "Pay a Lightning invoice", printHelpOnEmptyArgs = true) {
private val commonOptions by requireObject<HttpConf>()
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 fun run() { override suspend fun httpRequest() = commonOptions.httpClient.submitForm(
runBlocking {
val res = commonOptions.httpClient.submitForm(
url = (commonOptions.baseUrl / "payinvoice").toString(), url = (commonOptions.baseUrl / "payinvoice").toString(),
formParameters = parameters { formParameters = parameters {
amountSat?.let { append("amountSat", amountSat.toString()) } amountSat?.let { append("amountSat", amountSat.toString()) }
append("invoice", invoice) append("invoice", invoice)
} }
) )
echo(res.bodyAsText())
}
}
} }
class SendToAddress : CliktCommand(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 commonOptions by requireObject<HttpConf>()
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 fun run() { override suspend fun httpRequest() = commonOptions.httpClient.submitForm(
runBlocking {
val res = commonOptions.httpClient.submitForm(
url = (commonOptions.baseUrl / "sendtoaddress").toString(), url = (commonOptions.baseUrl / "sendtoaddress").toString(),
formParameters = parameters { formParameters = parameters {
append("amountSat", amountSat.toString()) append("amountSat", amountSat.toString())
@ -211,19 +175,13 @@ class SendToAddress : CliktCommand(name = "sendtoaddress", help = "Send to a Bit
append("feerateSatByte", feerateSatByte.toString()) append("feerateSatByte", feerateSatByte.toString())
} }
) )
echo(res.bodyAsText())
}
}
} }
class CloseChannel : CliktCommand(name = "closechannel", help = "Close channel", printHelpOnEmptyArgs = true) { class CloseChannel : PhoenixCliCommand(name = "closechannel", help = "Close channel", printHelpOnEmptyArgs = true) {
private val commonOptions by requireObject<HttpConf>()
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 fun run() { override suspend fun httpRequest() = commonOptions.httpClient.submitForm(
runBlocking {
val res = commonOptions.httpClient.submitForm(
url = (commonOptions.baseUrl / "closechannel").toString(), url = (commonOptions.baseUrl / "closechannel").toString(),
formParameters = parameters { formParameters = parameters {
append("channelId", channelId.toHex()) append("channelId", channelId.toHex())
@ -231,9 +189,6 @@ class CloseChannel : CliktCommand(name = "closechannel", help = "Close channel",
append("feerateSatByte", feerateSatByte.toString()) append("feerateSatByte", feerateSatByte.toString())
} }
) )
echo(res.bodyAsText())
}
}
} }
operator fun Url.div(path: String) = Url(URLBuilder(this).appendPathSegments(path)) operator fun Url.div(path: String) = Url(URLBuilder(this).appendPathSegments(path))