use crate::config::Common;
use crate::protocol::secrets::SecretKey;
use anyhow::{bail, Result};
use bytes::Bytes;
use netidx::{protocol::value::Value, utils::pack};
use netidx_protocols::{call_rpc, rpc::client::Proc};
use serde::de::DeserializeOwned;
pub struct SecretsQueryApi {
add_secret: Proc,
delete_secret: Proc,
list_secrets: Proc,
get_secret: Proc,
}
impl SecretsQueryApi {
pub async fn new(common: &Common) -> Result<Self> {
let base = common.paths.core_secrets();
let subscriber = &common.subscriber;
Ok(Self {
add_secret: Proc::new(subscriber, base.append("add-secret")).await?,
delete_secret: Proc::new(subscriber, base.append("delete-secret")).await?,
list_secrets: Proc::new(subscriber, base.append("list-secrets")).await?,
get_secret: Proc::new(subscriber, base.append("get-secret")).await?,
})
}
pub async fn add_secret(&self, secret_key: SecretKey, value: &[u8]) -> Result<()> {
let value = Value::Bytes(Bytes::copy_from_slice(value));
let res =
call_rpc!(&self.add_secret, secret_key: secret_key, value: value).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Ok => Ok(()),
_ => bail!("unexpected response"),
}
}
pub async fn delete_secret(&self, secret_key: SecretKey) -> Result<()> {
let res = call_rpc!(&self.delete_secret, secret_key: secret_key).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Ok => Ok(()),
_ => bail!("unexpected response"),
}
}
pub async fn list_secrets(&self) -> Result<Vec<SecretKey>> {
let args: [(&'static str, Value); 0] = [];
let res = self.list_secrets.call(args).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
v => Ok(v.cast_to()?),
}
}
pub async fn get_secret(&self, secret_key: SecretKey) -> Result<Option<Vec<u8>>> {
let secret_key = Value::Bytes(pack(&secret_key)?.freeze());
let res = call_rpc!(&self.get_secret, secret_key: secret_key).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
v => Ok(v.cast_to()?),
}
}
pub async fn get_any_exchangekey_secret_for_venue<T: DeserializeOwned>(
&self,
venue: &crate::protocol::symbology::Venue,
) -> Result<T> {
match self.list_secrets().await?.into_iter().find(|secret_key| match secret_key {
SecretKey::ExchangeKey(_label, venue1, _account) => *venue1 == *venue,
SecretKey::EVMKey(_, _) => false,
}) {
None => bail!("no exchange key found for {:?}", venue),
Some(secret_key) => {
let creds_json = self.get_secret(secret_key).await?.unwrap();
let creds: T = serde_json::from_str(std::str::from_utf8(&creds_json)?)?;
Ok(creds)
}
}
}
}