use super::super::{event::Event, payload::Payload};
use super::callback::Callback;
use super::client::Client;
use crate::RawClient;
use native_tls::TlsConnector;
use rust_engineio::client::ClientBuilder as EngineIoClientBuilder;
use rust_engineio::header::{HeaderMap, HeaderValue};
use url::Url;
use crate::client::callback::{SocketAnyCallback, SocketCallback};
use crate::error::Result;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use crate::socket::Socket as InnerSocket;
#[derive(Clone, Eq, PartialEq)]
pub enum TransportType {
Any,
Websocket,
WebsocketUpgrade,
Polling,
}
#[derive(Clone)]
pub struct ClientBuilder {
address: String,
on: Arc<Mutex<HashMap<Event, Callback<SocketCallback>>>>,
on_any: Arc<Mutex<Option<Callback<SocketAnyCallback>>>>,
namespace: String,
tls_config: Option<TlsConnector>,
opening_headers: Option<HeaderMap>,
transport_type: TransportType,
auth: Option<serde_json::Value>,
pub(crate) reconnect: bool,
pub(crate) max_reconnect_attempts: Option<u8>,
pub(crate) reconnect_delay_min: u64,
pub(crate) reconnect_delay_max: u64,
}
impl ClientBuilder {
pub fn new<T: Into<String>>(address: T) -> Self {
Self {
address: address.into(),
on: Arc::new(Mutex::new(HashMap::new())),
on_any: Arc::new(Mutex::new(None)),
namespace: "/".to_owned(),
tls_config: None,
opening_headers: None,
transport_type: TransportType::Any,
auth: None,
reconnect: true,
max_reconnect_attempts: None,
reconnect_delay_min: 1000,
reconnect_delay_max: 5000,
}
}
pub fn namespace<T: Into<String>>(mut self, namespace: T) -> Self {
let mut nsp = namespace.into();
if !nsp.starts_with('/') {
nsp = "/".to_owned() + &nsp;
}
self.namespace = nsp;
self
}
pub fn reconnect(mut self, reconnect: bool) -> Self {
self.reconnect = reconnect;
self
}
pub fn reconnect_delay(mut self, min: u64, max: u64) -> Self {
self.reconnect_delay_min = min;
self.reconnect_delay_max = max;
self
}
pub fn max_reconnect_attempts(mut self, reconnect_attempts: u8) -> Self {
self.max_reconnect_attempts = Some(reconnect_attempts);
self
}
#[allow(unused_mut)]
pub fn on<T: Into<Event>, F>(mut self, event: T, callback: F) -> Self
where
F: FnMut(Payload, RawClient) + 'static + Send,
{
let callback = Callback::<SocketCallback>::new(callback);
self.on.lock().unwrap().insert(event.into(), callback);
self
}
#[allow(unused_mut)]
pub fn on_any<F>(mut self, callback: F) -> Self
where
F: FnMut(Event, Payload, RawClient) + 'static + Send,
{
let callback = Some(Callback::<SocketAnyCallback>::new(callback));
*self.on_any.lock().unwrap() = callback;
self
}
pub fn tls_config(mut self, tls_config: TlsConnector) -> Self {
self.tls_config = Some(tls_config);
self
}
pub fn opening_header<T: Into<HeaderValue>, K: Into<String>>(mut self, key: K, val: T) -> Self {
match self.opening_headers {
Some(ref mut map) => {
map.insert(key.into(), val.into());
}
None => {
let mut map = HeaderMap::default();
map.insert(key.into(), val.into());
self.opening_headers = Some(map);
}
}
self
}
pub fn auth(mut self, auth: serde_json::Value) -> Self {
self.auth = Some(auth);
self
}
pub fn transport_type(mut self, transport_type: TransportType) -> Self {
self.transport_type = transport_type;
self
}
pub fn connect(self) -> Result<Client> {
Client::new(self)
}
pub fn connect_raw(self) -> Result<RawClient> {
let mut url = Url::parse(&self.address)?;
if url.path() == "/" {
url.set_path("/socket.io/");
}
let mut builder = EngineIoClientBuilder::new(url);
if let Some(tls_config) = self.tls_config {
builder = builder.tls_config(tls_config);
}
if let Some(headers) = self.opening_headers {
builder = builder.headers(headers);
}
let engine_client = match self.transport_type {
TransportType::Any => builder.build_with_fallback()?,
TransportType::Polling => builder.build_polling()?,
TransportType::Websocket => builder.build_websocket()?,
TransportType::WebsocketUpgrade => builder.build_websocket_with_upgrade()?,
};
let inner_socket = InnerSocket::new(engine_client)?;
let socket = RawClient::new(
inner_socket,
&self.namespace,
self.on,
self.on_any,
self.auth,
)?;
socket.connect()?;
Ok(socket)
}
}