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 }