mint_rpc_cli.rs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. use std::path::PathBuf;
  2. use anyhow::{anyhow, Result};
  3. use cdk_mint_rpc::cdk_mint_client::CdkMintClient;
  4. use cdk_mint_rpc::mint_rpc_cli::subcommands;
  5. use cdk_mint_rpc::GetInfoRequest;
  6. use clap::{Parser, Subcommand};
  7. use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity};
  8. use tonic::Request;
  9. use tracing::Level;
  10. use tracing_subscriber::EnvFilter;
  11. const DEFAULT_WORK_DIR: &str = ".cdk-mint-rpc-cli";
  12. #[derive(Parser)]
  13. #[command(version, about, long_about = None)]
  14. struct Cli {
  15. /// Address of RPC server
  16. #[arg(short, long, default_value = "https://127.0.0.1:8086")]
  17. addr: String,
  18. /// Logging level
  19. #[arg(short, long, default_value = "debug")]
  20. log_level: Level,
  21. /// Path to working dir
  22. #[arg(short, long)]
  23. work_dir: Option<PathBuf>,
  24. #[command(subcommand)]
  25. command: Commands,
  26. }
  27. #[derive(Subcommand)]
  28. enum Commands {
  29. /// Get info
  30. GetInfo,
  31. /// Update motd
  32. UpdateMotd(subcommands::UpdateMotdCommand),
  33. /// Update short description
  34. UpdateShortDescription(subcommands::UpdateShortDescriptionCommand),
  35. /// Update long description
  36. UpdateLongDescription(subcommands::UpdateLongDescriptionCommand),
  37. /// Update name
  38. UpdateName(subcommands::UpdateNameCommand),
  39. /// Update icon url
  40. UpdateIconUrl(subcommands::UpdateIconUrlCommand),
  41. /// Add Url
  42. AddUrl(subcommands::AddUrlCommand),
  43. /// Remove Url
  44. RemoveUrl(subcommands::RemoveUrlCommand),
  45. /// Add contact
  46. AddContact(subcommands::AddContactCommand),
  47. /// Remove contact
  48. RemoveContact(subcommands::RemoveContactCommand),
  49. /// Update nut04
  50. UpdateNut04(subcommands::UpdateNut04Command),
  51. /// Update nut05
  52. UpdateNut05(subcommands::UpdateNut05Command),
  53. /// Update quote ttl
  54. UpdateQuoteTtl(subcommands::UpdateQuoteTtlCommand),
  55. /// Get quote ttl
  56. GetQuoteTtl,
  57. /// Update Nut04 quote
  58. UpdateNut04QuoteState(subcommands::UpdateNut04QuoteCommand),
  59. /// Rotate next keyset
  60. RotateNextKeyset(subcommands::RotateNextKeysetCommand),
  61. }
  62. #[tokio::main]
  63. async fn main() -> Result<()> {
  64. let args: Cli = Cli::parse();
  65. let default_filter = args.log_level;
  66. let sqlx_filter = "sqlx=warn,hyper_util=warn,reqwest=warn";
  67. let env_filter = EnvFilter::new(format!("{},{}", default_filter, sqlx_filter));
  68. // Parse input
  69. tracing_subscriber::fmt().with_env_filter(env_filter).init();
  70. let cli = Cli::parse();
  71. let work_dir = match &args.work_dir {
  72. Some(work_dir) => work_dir.clone(),
  73. None => {
  74. let home_dir = home::home_dir().ok_or(anyhow!("Could not find home dir"))?;
  75. home_dir.join(DEFAULT_WORK_DIR)
  76. }
  77. };
  78. std::fs::create_dir_all(&work_dir)?;
  79. tracing::debug!("Using work dir: {}", work_dir.display());
  80. let channel = if work_dir.join("tls").is_dir() {
  81. // TLS directory exists, configure TLS
  82. let server_root_ca_cert = std::fs::read_to_string(work_dir.join("tls/ca.pem")).unwrap();
  83. let server_root_ca_cert = Certificate::from_pem(server_root_ca_cert);
  84. let client_cert = std::fs::read_to_string(work_dir.join("tls/client.pem"))?;
  85. let client_key = std::fs::read_to_string(work_dir.join("tls/client.key"))?;
  86. let client_identity = Identity::from_pem(client_cert, client_key);
  87. let tls = ClientTlsConfig::new()
  88. .ca_certificate(server_root_ca_cert)
  89. .identity(client_identity);
  90. Channel::from_shared(cli.addr.to_string())?
  91. .tls_config(tls)?
  92. .connect()
  93. .await?
  94. } else {
  95. // No TLS directory, skip TLS configuration
  96. Channel::from_shared(cli.addr.to_string())?
  97. .connect()
  98. .await?
  99. };
  100. let mut client = CdkMintClient::new(channel);
  101. match cli.command {
  102. Commands::GetInfo => {
  103. let response = client.get_info(Request::new(GetInfoRequest {})).await?;
  104. let info = response.into_inner();
  105. println!(
  106. "name: {}",
  107. info.name.unwrap_or("None".to_string())
  108. );
  109. println!(
  110. "version: {}",
  111. info.version.unwrap_or("None".to_string())
  112. );
  113. println!(
  114. "description: {}",
  115. info.description.unwrap_or("None".to_string())
  116. );
  117. println!(
  118. "long description: {}",
  119. info.long_description.unwrap_or("None".to_string())
  120. );
  121. println!("motd: {}", info.motd.unwrap_or("None".to_string()));
  122. println!("icon_url: {}", info.icon_url.unwrap_or("None".to_string()));
  123. for url in info.urls {
  124. println!("mint_url: {}", url);
  125. }
  126. for contact in info.contact {
  127. println!("method: {}, info: {}", contact.method, contact.info);
  128. }
  129. println!("total issued: {} sat", info.total_issued);
  130. println!("total redeemed: {} sat", info.total_redeemed);
  131. }
  132. Commands::UpdateMotd(sub_command_args) => {
  133. subcommands::update_motd(&mut client, &sub_command_args).await?;
  134. }
  135. Commands::UpdateShortDescription(sub_command_args) => {
  136. subcommands::update_short_description(&mut client, &sub_command_args).await?;
  137. }
  138. Commands::UpdateLongDescription(sub_command_args) => {
  139. subcommands::update_long_description(&mut client, &sub_command_args).await?;
  140. }
  141. Commands::UpdateName(sub_command_args) => {
  142. subcommands::update_name(&mut client, &sub_command_args).await?;
  143. }
  144. Commands::UpdateIconUrl(sub_command_args) => {
  145. subcommands::update_icon_url(&mut client, &sub_command_args).await?;
  146. }
  147. Commands::AddUrl(sub_command_args) => {
  148. subcommands::add_url(&mut client, &sub_command_args).await?;
  149. }
  150. Commands::RemoveUrl(sub_command_args) => {
  151. subcommands::remove_url(&mut client, &sub_command_args).await?;
  152. }
  153. Commands::AddContact(sub_command_args) => {
  154. subcommands::add_contact(&mut client, &sub_command_args).await?;
  155. }
  156. Commands::RemoveContact(sub_command_args) => {
  157. subcommands::remove_contact(&mut client, &sub_command_args).await?;
  158. }
  159. Commands::UpdateNut04(sub_command_args) => {
  160. subcommands::update_nut04(&mut client, &sub_command_args).await?;
  161. }
  162. Commands::UpdateNut05(sub_command_args) => {
  163. subcommands::update_nut05(&mut client, &sub_command_args).await?;
  164. }
  165. Commands::GetQuoteTtl => {
  166. subcommands::get_quote_ttl(&mut client).await?;
  167. }
  168. Commands::UpdateQuoteTtl(sub_command_args) => {
  169. subcommands::update_quote_ttl(&mut client, &sub_command_args).await?;
  170. }
  171. Commands::UpdateNut04QuoteState(sub_command_args) => {
  172. subcommands::update_nut04_quote_state(&mut client, &sub_command_args).await?;
  173. }
  174. Commands::RotateNextKeyset(sub_command_args) => {
  175. subcommands::rotate_next_keyset(&mut client, &sub_command_args).await?;
  176. }
  177. }
  178. Ok(())
  179. }