cli.rs
  1  use std::str::FromStr as _;
  2  use std::{ffi, iter};
  3  
  4  use anyhow::Context as _;
  5  use clap::Parser;
  6  use fedimint_meta_common::{MetaConsensusValue, MetaKey, MetaValue, DEFAULT_META_KEY};
  7  use serde::Serialize;
  8  use serde_json::json;
  9  
 10  use super::MetaClientModule;
 11  use crate::api::MetaFederationApi;
 12  
 13  #[derive(Parser, Serialize)]
 14  enum Opts {
 15      /// Get current consensus value
 16      Get {
 17          #[arg(long, default_value_t = DEFAULT_META_KEY)]
 18          key: MetaKey,
 19          #[arg(long)]
 20          hex: bool,
 21      },
 22      /// Get current consensus value revision
 23      GetRev {
 24          #[arg(long, default_value_t = DEFAULT_META_KEY)]
 25          key: MetaKey,
 26      },
 27      /// Get value change submissions
 28      GetSubmissions {
 29          #[arg(long, default_value_t = DEFAULT_META_KEY)]
 30          key: MetaKey,
 31          #[arg(long)]
 32          hex: bool,
 33      },
 34      /// Submit value change proposal
 35      Submit {
 36          #[arg(long, default_value_t = DEFAULT_META_KEY)]
 37          key: MetaKey,
 38          value: String,
 39          #[arg(long)]
 40          hex: bool,
 41      },
 42  }
 43  
 44  pub(crate) async fn handle_cli_command(
 45      meta: &MetaClientModule,
 46      args: &[ffi::OsString],
 47  ) -> anyhow::Result<serde_json::Value> {
 48      let opts = Opts::parse_from(iter::once(&ffi::OsString::from("meta")).chain(args.iter()));
 49  
 50      let res = match opts {
 51          Opts::Get { key, hex } => {
 52              if let Some(MetaConsensusValue { revision, value }) =
 53                  meta.module_api.get_consensus(key).await?
 54              {
 55                  let value = if hex {
 56                      serde_json::to_value(value).expect("can't fail")
 57                  } else {
 58                      value
 59                          .to_json_lossy()
 60                          .context("deserializing consensus value as json")?
 61                  };
 62                  json!({
 63                      "revision": revision,
 64                      "value": value
 65                  })
 66              } else {
 67                  serde_json::Value::Null
 68              }
 69          }
 70          Opts::GetRev { key } => {
 71              if let Some(rev) = meta.module_api.get_consensus_rev(key).await? {
 72                  json!({
 73                      "revision": rev,
 74                  })
 75              } else {
 76                  serde_json::Value::Null
 77              }
 78          }
 79          Opts::GetSubmissions { key, hex } => {
 80              let submissions = meta
 81                  .module_api
 82                  .get_submissions(key, meta.admin_auth()?)
 83                  .await?;
 84              let submissions: serde_json::Map<String, serde_json::Value> = submissions
 85                  .into_iter()
 86                  .map(|(peer_id, value)| -> anyhow::Result<_> {
 87                      let value = if hex {
 88                          serde_json::Value::String(value.to_string())
 89                      } else {
 90                          serde_json::from_reader(value.as_slice())
 91                              .context("deserializing submission value")?
 92                      };
 93  
 94                      Ok((peer_id.to_string(), value))
 95                  })
 96                  .collect::<anyhow::Result<_, _>>()?;
 97  
 98              serde_json::Value::Object(submissions)
 99          }
100          Opts::Submit { key, value, hex } => {
101              let value: MetaValue = if hex {
102                  MetaValue::from_str(&value).context("value not a valid hex string")?
103              } else {
104                  let _valid_json: serde_json::Value =
105                      serde_json::from_str(&value).context("value not a valid json string")?;
106                  MetaValue::from(value.as_bytes())
107              };
108  
109              meta.module_api
110                  .submit(key, value, meta.admin_auth()?)
111                  .await?;
112  
113              serde_json::Value::Bool(true)
114          }
115      };
116  
117      Ok(res)
118  }