use std::collections::HashMap;
use vta_sdk::prelude::*;
use vta_sdk::protocols::vta_management::update_config::UpdateConfigBody;
pub async fn cmd_config_get(
client: &VtaClient,
label_prefix: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let resp = client.get_config().await?;
let width = resp
.config
.fields
.iter()
.map(|f| f.key.len() + 1)
.max()
.unwrap_or(0)
.max(12);
for field in &resp.config.fields {
let value = match &field.value {
serde_json::Value::Null => "(not set)".to_string(),
serde_json::Value::String(s) => s.clone(),
other => other.to_string(),
};
let restart = if field.requires_restart {
" (requires restart)"
} else {
""
};
println!(
"{label_prefix}{:<width$} {value} [{}]{restart}",
format!("{}:", field.key),
field.source
);
}
Ok(())
}
pub async fn cmd_config_update(
client: &VtaClient,
label_prefix: &str,
vta_name: Option<String>,
public_url: Option<String>,
) -> Result<(), Box<dyn std::error::Error>> {
cmd_config_patch(
client,
label_prefix,
vta_name,
public_url,
RateLimitOverrides::default(),
)
.await
}
#[derive(Debug, Default, Clone, Copy)]
#[non_exhaustive]
pub struct RateLimitOverrides {
pub rate_limit_interval_secs: Option<u64>,
pub rate_limit_burst: Option<u32>,
pub did_log_rate_limit_interval_secs: Option<u64>,
pub did_log_rate_limit_burst: Option<u32>,
}
impl RateLimitOverrides {
fn entries(&self) -> Vec<(&'static str, serde_json::Value)> {
[
(
vta_sdk::rate_limit::VTA_INTERVAL_KEY,
self.rate_limit_interval_secs.map(serde_json::Value::from),
),
(
vta_sdk::rate_limit::VTA_BURST_KEY,
self.rate_limit_burst.map(serde_json::Value::from),
),
(
vta_sdk::rate_limit::VTA_DID_LOG_INTERVAL_KEY,
self.did_log_rate_limit_interval_secs
.map(serde_json::Value::from),
),
(
vta_sdk::rate_limit::VTA_DID_LOG_BURST_KEY,
self.did_log_rate_limit_burst.map(serde_json::Value::from),
),
]
.into_iter()
.filter_map(|(k, v)| v.map(|v| (k, v)))
.collect()
}
}
pub async fn cmd_config_patch(
client: &VtaClient,
label_prefix: &str,
vta_name: Option<String>,
public_url: Option<String>,
rate_limits: RateLimitOverrides,
) -> Result<(), Box<dyn std::error::Error>> {
let mut overrides = HashMap::new();
if let Some(v) = vta_name {
overrides.insert("vta_name".to_string(), serde_json::Value::String(v));
}
if let Some(v) = public_url {
overrides.insert("public_url".to_string(), serde_json::Value::String(v));
}
for (key, value) in rate_limits.entries() {
overrides.insert(key.to_string(), value);
}
if overrides.is_empty() {
println!(
"Nothing to update — pass at least one of --vta-name, --public-url, \
--rate-limit-interval-secs, --rate-limit-burst, \
--did-log-rate-limit-interval-secs or --did-log-rate-limit-burst."
);
return Ok(());
}
let resp = client
.update_config(UpdateConfigRequest {
patch: UpdateConfigBody::new(overrides),
})
.await?;
if !resp.applied.is_empty() {
println!(
"{label_prefix}Applied: {}",
resp.applied.join(", ")
);
}
if !resp.pending_restart.is_empty() {
println!(
"{label_prefix}Pending restart: {}",
resp.pending_restart.join(", ")
);
println!("{label_prefix} Stored, but not in effect until the VTA restarts.");
}
for rejected in &resp.rejected {
println!(
"{label_prefix}Rejected {}: {}",
rejected.key, rejected.reason
);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rate_limit_overrides_emit_only_set_keys_as_integers() {
assert!(RateLimitOverrides::default().entries().is_empty());
let o = RateLimitOverrides {
rate_limit_burst: Some(30),
did_log_rate_limit_interval_secs: Some(2),
..Default::default()
};
let entries = o.entries();
assert_eq!(
entries,
vec![
("rate_limit_burst", serde_json::json!(30)),
("did_log_rate_limit_interval_secs", serde_json::json!(2)),
]
);
}
}