use super::{broker_connection::BrokerConnection, ClientConfig, Result};
use crate::formats::{Read, RequestMessage, Write};
use futures::future::select_ok;
use std::{fmt::Debug, sync::Arc};
use tokio::sync::{MappedMutexGuard, Mutex, MutexGuard};
use tracing::trace;
#[derive(Debug, Clone)]
pub struct LazyBrokerConnection {
config: Arc<ClientConfig>,
conn: Arc<Mutex<Option<BrokerConnection>>>,
}
impl LazyBrokerConnection {
#[allow(unused)]
pub fn new(config: ClientConfig) -> Self {
LazyBrokerConnection {
config: Arc::new(config),
conn: Default::default(),
}
}
pub async fn send<Req: RequestMessage + Write + Debug, Resp: Read + Debug>(
&self,
message: Req,
) -> Result<Resp> {
self.get_connection().await?.send(message).await
}
pub async fn send_many<ReqM: RequestMessage + Write + Debug, Resp: Read + Debug>(
&self,
messages: impl IntoIterator<Item = ReqM>,
) -> Result<Vec<Resp>> {
self.get_connection().await?.send_many(messages).await
}
#[allow(unused)]
pub async fn get_connection(&self) -> Result<MappedMutexGuard<BrokerConnection>> {
let mut lock = self.conn.lock().await;
if lock.is_none() {
trace!("creating connection to");
lock.insert(self.connect_to_single_broker().await?);
}
Ok(MutexGuard::map(lock, |l| {
l.as_mut().expect("BrokerConnection is missing")
}))
}
#[allow(unused)]
pub async fn reset(&self) -> Result<()> {
trace!("resetting connection");
let mut lock = self.conn.lock().await;
let new_connection = self.connect_to_single_broker().await?;
if let Some(old_conn) = lock.replace(new_connection) {
old_conn.shutdown().await?;
}
Ok(())
}
async fn connect_to_single_broker(&self) -> Result<BrokerConnection> {
let (c, _) = select_ok(self.config.broker_list.iter().map(|address| {
Box::pin(BrokerConnection::connect(
self.config.client_id.clone(),
address.as_to_socket_address(),
))
}))
.await?;
Ok(c)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
clients::BrokerList,
formats::{
api::{ApiVersionsReq, ApiVersionsResp},
ErrorCode,
},
};
#[tokio::test]
async fn test_lazy_connection() {
let broker_list = BrokerList(vec!["localhost:9092".into()]);
let client_id = "test-client".into();
let client_config = ClientConfig {
broker_list,
client_id,
};
let conn = LazyBrokerConnection::new(client_config);
let resp: ApiVersionsResp = conn
.get_connection()
.await
.unwrap()
.send(ApiVersionsReq)
.await
.unwrap();
assert_eq!(resp.error_code, ErrorCode::None);
assert!(!resp.api_keys.is_empty())
}
}