use std::convert::TryInto;
use std::result::Result as StdResult;
use std::time::Duration;
use crate::broker::{ReconnectCondition, ReconnectConfig};
use crate::client::WebSocketClient;
use crate::error::{Error, Result};
use url::Url;
#[derive(Debug, Clone)]
struct WebSocketClientBuilderInner {
url: Url,
reconnect: ReconnectConfig,
}
#[derive(Debug, Clone)]
pub struct WebSocketClientBuilder {
inner: Result<WebSocketClientBuilderInner>,
}
trait ResultExt<T, E> {
fn and_then_mut<F>(&mut self, op: F)
where
F: FnOnce(&mut T) -> StdResult<(), E>;
}
impl<T, E> ResultExt<T, E> for StdResult<T, E> {
fn and_then_mut<F>(&mut self, f: F)
where
F: FnOnce(&mut T) -> StdResult<(), E>,
{
if let Ok(x) = self {
if let Err(e) = f(x) {
*self = Err(e);
}
}
}
}
impl WebSocketClientBuilder {
pub fn new<T>(url: T) -> Self
where
T: TryInto<Url>,
T::Error: Into<Error>,
{
let inner = url
.try_into()
.map_err(Into::into)
.map(|url| WebSocketClientBuilderInner {
url,
reconnect: ReconnectConfig::default(),
});
WebSocketClientBuilder { inner }
}
pub fn with_host<S>(host: S) -> Self
where
S: AsRef<str>,
{
let url = format!("wss://{}/streaming", host.as_ref());
WebSocketClientBuilder::new(url.as_str())
}
pub fn token<S>(&mut self, token: S) -> &mut Self
where
S: AsRef<str>,
{
self.query("i", token)
}
pub fn query<S1, S2>(&mut self, key: S1, value: S2) -> &mut Self
where
S1: AsRef<str>,
S2: AsRef<str>,
{
self.inner.and_then_mut(|inner| {
inner
.url
.query_pairs_mut()
.append_pair(key.as_ref(), value.as_ref());
Ok(())
});
self
}
pub fn auto_reconnect(&mut self, enable: bool) -> &mut Self {
if enable {
self.reconnect_condition(ReconnectCondition::unexpected_reset())
} else {
self.reconnect_condition(ReconnectCondition::never())
}
}
pub fn reconnect_secs(&mut self, secs: u64) -> &mut Self {
self.inner.and_then_mut(|inner| {
inner.reconnect.interval = Duration::from_secs(secs);
Ok(())
});
self
}
pub fn reconnect_interval(&mut self, interval: Duration) -> &mut Self {
self.inner.and_then_mut(|inner| {
inner.reconnect.interval = interval;
Ok(())
});
self
}
pub fn reconnect_condition(&mut self, condition: ReconnectCondition) -> &mut Self {
self.inner.and_then_mut(|inner| {
inner.reconnect.condition = condition;
Ok(())
});
self
}
pub fn reconnect_retry_send(&mut self, enable: bool) -> &mut Self {
self.inner.and_then_mut(|inner| {
inner.reconnect.retry_send = enable;
Ok(())
});
self
}
pub async fn connect(&self) -> Result<WebSocketClient> {
let WebSocketClientBuilderInner { url, reconnect } = match self.inner.clone() {
Err(e) => return Err(e),
Ok(inner) => inner,
};
WebSocketClient::connect_with_config(url, reconnect).await
}
}