use tonic::transport::{Channel, ClientTlsConfig}; use crate::grpc::{churn_client::ChurnClient, *}; #[derive(Clone)] pub struct GrpcClient { host: String, } impl GrpcClient { pub fn new(host: impl Into) -> Self { Self { host: host.into() } } pub async fn get_key( &self, namespace: &str, id: Option>, key: &str, ) -> anyhow::Result> { let mut client = self.client().await?; let resp = client .get_key(GetKeyRequest { key: key.into(), namespace: namespace.into(), id: id.map(|i| i.into()), }) .await?; let resp = resp.into_inner(); Ok(resp.value) } pub async fn set_key( &self, namespace: &str, id: Option>, key: &str, value: &str, ) -> anyhow::Result<()> { let mut client = self.client().await?; client .set_key(SetKeyRequest { key: key.into(), value: value.into(), namespace: namespace.into(), id: id.map(|i| i.into()), }) .await?; Ok(()) } pub async fn listen_events( &self, namespace: &str, id: Option>, exec: impl ListenEventsExecutor, ) -> anyhow::Result<()> { let mut client = self.client().await?; tracing::debug!("creating stream for listening to events on: {}", namespace); let resp = client .listen_events(ListenEventsRequest { namespace: namespace.into(), id: id.map(|i| i.into()), }) .await .inspect_err(|e| tracing::warn!("failed to establish a connection: {}", e))?; tracing::debug!("setup stream: {}", namespace); let mut inner = resp.into_inner(); while let Ok(Some(message)) = inner.message().await { tracing::debug!("received message: {}", namespace); exec.execute(message) .await .inspect_err(|e| tracing::warn!("failed to handle message: {}", e))?; } Ok(()) } async fn client(&self) -> anyhow::Result> { tracing::debug!("setting up client"); let channel = if self.host.starts_with("https") { Channel::from_shared(self.host.to_owned())? .tls_config(ClientTlsConfig::new().with_native_roots())? .connect_timeout(std::time::Duration::from_secs(5)) .connect() .await? } else { Channel::from_shared(self.host.to_owned())? .connect() .await? }; let client = ChurnClient::new(channel); Ok(client) } } #[async_trait::async_trait] pub trait ListenEventsExecutor { async fn execute(&self, event: ListenEventsResponse) -> anyhow::Result<()>; }