use std::time::Duration;
use tokio_tungstenite::tungstenite::{Message, client::IntoClientRequest, http};
use url::Url;
use crate::Error;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct ConnectOptions {
pub(crate) extra_headers: http::HeaderMap,
pub(crate) keepalive_interval: Option<Duration>,
pub(crate) custom_keepalive_message: Option<Message>,
}
impl Default for ConnectOptions {
fn default() -> Self {
Self {
extra_headers: http::HeaderMap::new(),
keepalive_interval: Some(Duration::from_secs(2)),
custom_keepalive_message: None,
}
}
}
impl ConnectOptions {
#[must_use]
pub fn builder() -> ConnectOptionsBuilder {
ConnectOptionsBuilder {
options: ConnectOptions::default(),
}
}
pub(crate) fn build_request(&self, url: &Url) -> Result<http::Request<()>, Error> {
let mut request = url
.as_str()
.into_client_request()
.map_err(Error::WebsocketError)?;
for (key, value) in &self.extra_headers {
request.headers_mut().insert(key, value.clone());
}
Ok(request)
}
}
#[derive(Clone, Debug)]
pub struct ConnectOptionsBuilder {
options: ConnectOptions,
}
impl ConnectOptionsBuilder {
#[must_use]
pub fn keepalive_interval(mut self, interval: Option<Duration>) -> Self {
self.options.keepalive_interval = interval;
self
}
#[must_use]
pub fn header<K: http::header::IntoHeaderName>(
mut self,
name: K,
value: http::HeaderValue,
) -> Self {
self.options.extra_headers.insert(name, value);
self
}
#[must_use]
pub fn headers(mut self, headers: http::HeaderMap) -> Self {
self.options.extra_headers = headers;
self
}
#[must_use]
pub fn custom_keepalive_message(mut self, message: Option<Message>) -> Self {
self.options.custom_keepalive_message = message;
self
}
#[must_use]
pub fn build(self) -> ConnectOptions {
self.options
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_default_matches_default() {
let built = ConnectOptions::builder().build();
let default = ConnectOptions::default();
assert_eq!(built.keepalive_interval, default.keepalive_interval);
assert_eq!(
built.custom_keepalive_message,
default.custom_keepalive_message
);
assert_eq!(built.extra_headers, default.extra_headers);
}
#[test]
fn builder_sets_each_field() {
let opts = ConnectOptions::builder()
.keepalive_interval(None)
.custom_keepalive_message(Some(Message::text("ping")))
.header("x-test", "v".parse().unwrap())
.build();
assert_eq!(opts.keepalive_interval, None);
assert_eq!(opts.custom_keepalive_message, Some(Message::text("ping")));
assert_eq!(opts.extra_headers.get("x-test").unwrap(), "v");
}
#[test]
fn headers_replaces_whole_map() {
let mut map = http::HeaderMap::new();
map.insert("a", "1".parse().unwrap());
map.insert("b", "2".parse().unwrap());
let opts = ConnectOptions::builder()
.header("z", "0".parse().unwrap())
.headers(map)
.build();
assert_eq!(opts.extra_headers.len(), 2);
assert_eq!(opts.extra_headers.get("a").unwrap(), "1");
assert!(opts.extra_headers.get("z").is_none());
}
}