use crate::error::WebSocketError;
use std::sync::Arc;
pub type MessageCallback = Arc<dyn Fn(&str) -> Result<(), WebSocketError> + Send + Sync>;
pub type ErrorCallback = Arc<dyn Fn(&str, &WebSocketError) + Send + Sync>;
#[derive(Clone)]
pub struct MessageHandler {
pub message_callback: MessageCallback,
pub error_callback: ErrorCallback,
}
impl MessageHandler {
pub fn new<F, E>(message_callback: F, error_callback: E) -> Self
where
F: Fn(&str) -> Result<(), WebSocketError> + Send + Sync + 'static,
E: Fn(&str, &WebSocketError) + Send + Sync + 'static,
{
Self {
message_callback: Arc::new(message_callback),
error_callback: Arc::new(error_callback),
}
}
pub fn handle_message(&self, message: &str) {
match (self.message_callback)(message) {
Ok(()) => {
}
Err(error) => {
(self.error_callback)(message, &error);
}
}
}
}
impl std::fmt::Debug for MessageHandler {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MessageHandler")
.field("message_callback", &"<callback function>")
.field("error_callback", &"<error callback function>")
.finish()
}
}
pub struct MessageHandlerBuilder {
message_callback: Option<MessageCallback>,
error_callback: Option<ErrorCallback>,
}
impl Default for MessageHandlerBuilder {
fn default() -> Self {
Self::new()
}
}
impl MessageHandlerBuilder {
pub fn new() -> Self {
Self {
message_callback: None,
error_callback: None,
}
}
pub fn with_message_callback<F>(mut self, callback: F) -> Self
where
F: Fn(&str) -> Result<(), WebSocketError> + Send + Sync + 'static,
{
self.message_callback = Some(Arc::new(callback));
self
}
pub fn with_error_callback<E>(mut self, callback: E) -> Self
where
E: Fn(&str, &WebSocketError) + Send + Sync + 'static,
{
self.error_callback = Some(Arc::new(callback));
self
}
pub fn build(self) -> Result<MessageHandler, WebSocketError> {
let message_callback = self.message_callback.ok_or_else(|| {
WebSocketError::InvalidMessage("Message callback is required".to_string())
})?;
let error_callback = self.error_callback.ok_or_else(|| {
WebSocketError::InvalidMessage("Error callback is required".to_string())
})?;
Ok(MessageHandler {
message_callback,
error_callback,
})
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
#[test]
fn test_message_handler_success() {
let handler = MessageHandler::new(
|_message| Ok(()),
|_message, _error| {
panic!("Error callback should not be called on success");
},
);
handler.handle_message("test message");
}
#[test]
fn test_message_handler_error() {
use std::sync::{Arc, Mutex};
let error_called = Arc::new(Mutex::new(false));
let error_called_clone = error_called.clone();
let handler = MessageHandler::new(
|_message| Err(WebSocketError::InvalidMessage("Test error".to_string())),
move |_message, _error| {
*error_called_clone.lock().unwrap() = true;
},
);
handler.handle_message("test message");
assert!(*error_called.lock().unwrap());
}
#[test]
fn test_message_handler_builder() {
let handler = MessageHandlerBuilder::new()
.with_message_callback(|_| Ok(()))
.with_error_callback(|_, _| {})
.build()
.unwrap();
handler.handle_message("test");
}
}