use futures::{future::BoxFuture, FutureExt};
use crate::{
builder::ClientBuilder,
emulator::{self, EmulatorData},
pubsub,
};
use tracing::debug;
type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
pub struct EmulatorClient {
inner: crate::emulator::EmulatorClient,
_temp: tempdir::TempDir,
}
fn data(tmp_dir: &tempdir::TempDir) -> EmulatorData {
EmulatorData {
gcloud_param: "pubsub",
kill_pattern: "pubsub",
availability_check: create_schema_client,
extra_args: vec!["--data-dir".into(), tmp_dir.path().into()],
}
}
impl EmulatorClient {
pub async fn new() -> Result<Self, BoxError> {
let temp = tempdir::TempDir::new("pubsub_emulator")?;
Ok(EmulatorClient {
inner: emulator::EmulatorClient::new(data(&temp)).await?,
_temp: temp,
})
}
pub async fn with_project(project_name: impl Into<String>) -> Result<Self, BoxError> {
let temp = tempdir::TempDir::new("pubsub_emulator")?;
debug!(
path = temp.as_ref().to_str(),
"Created emulator data directory"
);
let project_name = project_name.into();
Ok(EmulatorClient {
inner: emulator::EmulatorClient::with_project(data(&temp), project_name).await?,
_temp: temp,
})
}
pub fn endpoint(&self) -> String {
self.inner.endpoint()
}
pub fn project(&self) -> &str {
self.inner.project()
}
pub fn builder(&self) -> &ClientBuilder {
self.inner.builder()
}
pub async fn create_topic(&self, topic_name: impl AsRef<str>) -> Result<(), BoxError> {
let config = pubsub::PubSubConfig {
endpoint: self.endpoint(),
..pubsub::PubSubConfig::default()
};
let mut publisher = self.builder().build_pubsub_publisher(config).await?;
publisher
.create_topic(pubsub::api::Topic {
name: pubsub::ProjectTopicName::new(self.project(), topic_name.as_ref()).into(),
..pubsub::api::Topic::default()
})
.await?;
debug!(topic = topic_name.as_ref(), "Emulator created topic");
Ok(())
}
}
fn create_schema_client(port: &str) -> BoxFuture<Result<(), tonic::transport::Error>> {
async move {
pubsub::api::schema_service_client::SchemaServiceClient::connect(format!(
"http://{}:{}",
crate::emulator::HOST,
port
))
.await?;
Ok(())
}
.boxed()
}