use std::sync::Arc;
use crate::AtomicWebsocketType;
use super::{
internal_client::ClientOptions, internal_server::ServerOptions, middleware::MessageMiddleware,
};
#[derive(Default)]
pub struct ClientOptionsBuilder {
options: ClientOptions,
}
impl ClientOptionsBuilder {
pub fn new() -> Self {
Self {
options: ClientOptions::default(),
}
}
pub fn internal() -> Self {
Self {
options: ClientOptions {
atomic_websocket_type: AtomicWebsocketType::Internal,
..Default::default()
},
}
}
pub fn external(url: &str) -> Self {
Self {
options: ClientOptions {
atomic_websocket_type: AtomicWebsocketType::External,
url: url.to_owned(),
..Default::default()
},
}
}
pub fn url(mut self, url: &str) -> Self {
self.options.url = url.to_owned();
self
}
pub fn use_ping(mut self, use_ping: bool) -> Self {
self.options.use_ping = use_ping;
self
}
pub fn retry_seconds(mut self, seconds: u64) -> Self {
self.options.retry_seconds = seconds;
self
}
pub fn use_keep_ip(mut self, use_keep_ip: bool) -> Self {
self.options.use_keep_ip = use_keep_ip;
self
}
pub fn connect_timeout(mut self, seconds: u64) -> Self {
self.options.connect_timeout_seconds = seconds;
self
}
pub fn connection_type(mut self, connection_type: AtomicWebsocketType) -> Self {
self.options.atomic_websocket_type = connection_type;
self
}
#[cfg(feature = "rustls")]
pub fn use_tls(mut self, use_tls: bool) -> Self {
self.options.use_tls = use_tls;
self
}
pub fn handler_buffer_size(mut self, size: usize) -> Self {
self.options.handler_buffer_size = size;
self
}
pub fn status_buffer_size(mut self, size: usize) -> Self {
self.options.status_buffer_size = size;
self
}
pub fn per_connection_buffer_size(mut self, size: usize) -> Self {
self.options.per_connection_buffer_size = size;
self
}
pub fn spillover_buffer_size(mut self, size: usize) -> Self {
self.options.spillover_buffer_size = size;
self
}
pub fn build(self) -> ClientOptions {
self.options
}
}
#[derive(Default)]
pub struct ServerOptionsBuilder {
options: ServerOptions,
}
impl ServerOptionsBuilder {
pub fn new() -> Self {
Self {
options: ServerOptions::default(),
}
}
pub fn use_ping(mut self, use_ping: bool) -> Self {
self.options.use_ping = use_ping;
self
}
pub fn proxy_ping(mut self, category: i16) -> Self {
self.options.proxy_ping = category;
self
}
pub fn client_timeout_seconds(mut self, seconds: u64) -> Self {
self.options.client_timeout_seconds = seconds;
self
}
pub fn client_check_interval_secs(mut self, seconds: u64) -> Self {
self.options.client_check_interval_secs = seconds;
self
}
pub fn per_connection_buffer_size(mut self, size: usize) -> Self {
self.options.per_connection_buffer_size = size;
self
}
pub fn handler_buffer_size(mut self, size: usize) -> Self {
self.options.handler_buffer_size = size;
self
}
pub fn spillover_buffer_size(mut self, size: usize) -> Self {
self.options.spillover_buffer_size = size;
self
}
pub fn middleware(mut self, mw: Arc<dyn MessageMiddleware>) -> Self {
self.options.middlewares.push(mw);
self
}
#[cfg(feature = "rustls")]
pub fn tls_config(mut self, config: std::sync::Arc<rustls::ServerConfig>) -> Self {
self.options.tls_config = Some(config);
self
}
#[cfg(feature = "rustls")]
pub fn tls_from_pem(mut self, cert_path: &str, key_path: &str) -> std::io::Result<Self> {
use std::io::{BufReader, ErrorKind};
use std::sync::Arc;
let cert_file = std::fs::File::open(cert_path)?;
let key_file = std::fs::File::open(key_path)?;
let certs: Vec<_> =
rustls_pemfile::certs(&mut BufReader::new(cert_file)).collect::<Result<_, _>>()?;
let key = rustls_pemfile::private_key(&mut BufReader::new(key_file))?
.ok_or_else(|| std::io::Error::new(ErrorKind::InvalidData, "no private key found"))?;
let config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, key)
.map_err(|e| std::io::Error::new(ErrorKind::InvalidData, e))?;
self.options.tls_config = Some(Arc::new(config));
Ok(self)
}
pub fn build(self) -> ServerOptions {
self.options
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_client_options_builder_defaults() {
let options = ClientOptionsBuilder::new().build();
assert!(options.use_ping);
assert_eq!(options.retry_seconds, 30);
assert_eq!(options.connect_timeout_seconds, 3);
}
#[test]
fn test_client_options_builder_internal() {
let options = ClientOptionsBuilder::internal()
.use_ping(false)
.retry_seconds(60)
.build();
assert!(!options.use_ping);
assert_eq!(options.retry_seconds, 60);
assert!(matches!(
options.atomic_websocket_type,
AtomicWebsocketType::Internal
));
}
#[test]
fn test_client_options_builder_external() {
let options = ClientOptionsBuilder::external("example.com:9000")
.connect_timeout(10)
.build();
assert_eq!(options.url, "example.com:9000");
assert_eq!(options.connect_timeout_seconds, 10);
assert!(matches!(
options.atomic_websocket_type,
AtomicWebsocketType::External
));
}
#[test]
fn test_server_options_builder() {
let options = ServerOptionsBuilder::new()
.use_ping(false)
.proxy_ping(100)
.build();
assert!(!options.use_ping);
assert_eq!(options.proxy_ping, 100);
}
}