168 lines
6.1 KiB
Rust
168 lines
6.1 KiB
Rust
// file: crates/common/game-realtime-websocket-lib/src/config.rs
|
|
// version: 1
|
|
|
|
const DEFAULT_CLOSE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(2);
|
|
const DEFAULT_CONNECT_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
|
const DEFAULT_MAX_FRAME_SIZE: usize = 1024 * 1024;
|
|
const DEFAULT_MAX_MESSAGE_SIZE: usize = 1024 * 1024;
|
|
const DEFAULT_MAX_WRITE_BUFFER_SIZE: usize = 2 * 1024 * 1024;
|
|
const DEFAULT_SEND_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
|
|
const DEFAULT_WRITE_BUFFER_SIZE: usize = 64 * 1024;
|
|
|
|
/// Product-facing limits and operation deadlines for one WebSocket connection.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub struct WebSocketConfig {
|
|
max_message_size: usize,
|
|
max_frame_size: usize,
|
|
write_buffer_size: usize,
|
|
max_write_buffer_size: usize,
|
|
connect_timeout: std::time::Duration,
|
|
send_timeout: std::time::Duration,
|
|
close_timeout: std::time::Duration,
|
|
}
|
|
|
|
impl Default for WebSocketConfig {
|
|
fn default() -> Self {
|
|
return Self {
|
|
max_message_size: DEFAULT_MAX_MESSAGE_SIZE,
|
|
max_frame_size: DEFAULT_MAX_FRAME_SIZE,
|
|
write_buffer_size: DEFAULT_WRITE_BUFFER_SIZE,
|
|
max_write_buffer_size: DEFAULT_MAX_WRITE_BUFFER_SIZE,
|
|
connect_timeout: DEFAULT_CONNECT_TIMEOUT,
|
|
send_timeout: DEFAULT_SEND_TIMEOUT,
|
|
close_timeout: DEFAULT_CLOSE_TIMEOUT,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl WebSocketConfig {
|
|
/// Returns a copy with a different maximum binary message size.
|
|
#[must_use]
|
|
pub fn with_max_message_size(mut self, value: usize) -> Self {
|
|
self.max_message_size = value;
|
|
return self;
|
|
}
|
|
|
|
/// Returns a copy with a different maximum WebSocket frame payload size.
|
|
#[must_use]
|
|
pub fn with_max_frame_size(mut self, value: usize) -> Self {
|
|
self.max_frame_size = value;
|
|
return self;
|
|
}
|
|
|
|
/// Returns a copy with a different Tungstenite write-buffer target.
|
|
#[must_use]
|
|
pub fn with_write_buffer_size(mut self, value: usize) -> Self {
|
|
self.write_buffer_size = value;
|
|
return self;
|
|
}
|
|
|
|
/// Returns a copy with a different hard maximum for the Tungstenite write buffer.
|
|
#[must_use]
|
|
pub fn with_max_write_buffer_size(mut self, value: usize) -> Self {
|
|
self.max_write_buffer_size = value;
|
|
return self;
|
|
}
|
|
|
|
/// Returns a copy with a different connection or handshake deadline.
|
|
#[must_use]
|
|
pub fn with_connect_timeout(mut self, value: std::time::Duration) -> Self {
|
|
self.connect_timeout = value;
|
|
return self;
|
|
}
|
|
|
|
/// Returns a copy with a different deadline for one send operation.
|
|
#[must_use]
|
|
pub fn with_send_timeout(mut self, value: std::time::Duration) -> Self {
|
|
self.send_timeout = value;
|
|
return self;
|
|
}
|
|
|
|
/// Returns a copy with a different deadline for a clean local close operation.
|
|
#[must_use]
|
|
pub fn with_close_timeout(mut self, value: std::time::Duration) -> Self {
|
|
self.close_timeout = value;
|
|
return self;
|
|
}
|
|
|
|
/// Returns the configured maximum binary message size.
|
|
#[must_use]
|
|
pub fn max_message_size(&self) -> usize {
|
|
return self.max_message_size;
|
|
}
|
|
|
|
/// Returns the configured maximum WebSocket frame payload size.
|
|
#[must_use]
|
|
pub fn max_frame_size(&self) -> usize {
|
|
return self.max_frame_size;
|
|
}
|
|
|
|
/// Returns the configured Tungstenite write-buffer target.
|
|
#[must_use]
|
|
pub fn write_buffer_size(&self) -> usize {
|
|
return self.write_buffer_size;
|
|
}
|
|
|
|
/// Returns the configured hard maximum for the Tungstenite write buffer.
|
|
#[must_use]
|
|
pub fn max_write_buffer_size(&self) -> usize {
|
|
return self.max_write_buffer_size;
|
|
}
|
|
|
|
/// Returns the configured connection or handshake deadline.
|
|
#[must_use]
|
|
pub fn connect_timeout(&self) -> std::time::Duration {
|
|
return self.connect_timeout;
|
|
}
|
|
|
|
/// Returns the configured deadline for one send operation.
|
|
#[must_use]
|
|
pub fn send_timeout(&self) -> std::time::Duration {
|
|
return self.send_timeout;
|
|
}
|
|
|
|
/// Returns the configured deadline for a clean local close operation.
|
|
#[must_use]
|
|
pub fn close_timeout(&self) -> std::time::Duration {
|
|
return self.close_timeout;
|
|
}
|
|
|
|
/// Validates all invariants required before creating a WebSocket endpoint or connection.
|
|
pub fn validate(&self) -> Result<(), game_realtime_transport_lib::TransportError> {
|
|
if self.max_message_size == 0 {
|
|
return Err(invalid_configuration("max_message_size must be greater than zero"));
|
|
}
|
|
if self.max_frame_size == 0 {
|
|
return Err(invalid_configuration("max_frame_size must be greater than zero"));
|
|
}
|
|
if self.max_frame_size > self.max_message_size {
|
|
return Err(invalid_configuration("max_frame_size must not exceed max_message_size"));
|
|
}
|
|
let minimum_max_write_buffer_size = match self.write_buffer_size.checked_add(self.max_message_size) {
|
|
Some(value) => value,
|
|
None => return Err(invalid_configuration("write_buffer_size + max_message_size overflows usize")),
|
|
};
|
|
if self.max_write_buffer_size < minimum_max_write_buffer_size {
|
|
return Err(invalid_configuration("max_write_buffer_size must fit write_buffer_size plus one maximum-sized message"));
|
|
}
|
|
if self.connect_timeout.is_zero() {
|
|
return Err(invalid_configuration("connect_timeout must be greater than zero"));
|
|
}
|
|
if self.send_timeout.is_zero() {
|
|
return Err(invalid_configuration("send_timeout must be greater than zero"));
|
|
}
|
|
if self.close_timeout.is_zero() {
|
|
return Err(invalid_configuration("close_timeout must be greater than zero"));
|
|
}
|
|
return Ok(());
|
|
}
|
|
}
|
|
|
|
fn invalid_configuration(detail: &str) -> game_realtime_transport_lib::TransportError {
|
|
return game_realtime_transport_lib::TransportError::new(game_realtime_transport_lib::TransportErrorKind::InvalidConfiguration, detail);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "../unit_tests/config.rs"]
|
|
mod tests;
|