huskies: merge 612_story_extract_ws_service
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
//! Typed error enum for the WebSocket service layer.
|
||||
//!
|
||||
//! Every distinct failure mode the WS layer can produce is represented here.
|
||||
//! The HTTP/WS adapter maps these to close codes or error frames.
|
||||
|
||||
/// Errors produced by the WebSocket service layer.
|
||||
///
|
||||
/// Each variant maps to a distinct failure mode; the transport adapter
|
||||
/// translates these into WS close codes or error-frame messages.
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Error {
|
||||
/// Client sent a message that could not be parsed as a valid `WsRequest`.
|
||||
/// Maps to an `error` frame with the parse failure detail.
|
||||
InvalidMessage(String),
|
||||
/// The chat subsystem returned an error (e.g. LLM provider failure).
|
||||
/// Maps to an `error` frame with the provider message.
|
||||
Chat(String),
|
||||
/// A permission response referenced an unknown `request_id`.
|
||||
/// Silently ignored in practice (no frame sent), but tracked for observability.
|
||||
UnknownPermissionRequest(String),
|
||||
/// Failed to load initial state (pipeline, onboarding, wizard).
|
||||
/// Maps to an `error` frame.
|
||||
Init(String),
|
||||
/// The send channel to the client is closed (client disconnected).
|
||||
/// Triggers connection teardown — no frame is sent.
|
||||
ClientGone,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InvalidMessage(msg) => write!(f, "Invalid request: {msg}"),
|
||||
Self::Chat(msg) => write!(f, "Chat error: {msg}"),
|
||||
Self::UnknownPermissionRequest(id) => {
|
||||
write!(f, "Unknown permission request: {id}")
|
||||
}
|
||||
Self::Init(msg) => write!(f, "Initialisation error: {msg}"),
|
||||
Self::ClientGone => write!(f, "Client disconnected"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn display_invalid_message() {
|
||||
let err = Error::InvalidMessage("bad json".to_string());
|
||||
assert_eq!(err.to_string(), "Invalid request: bad json");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_chat_error() {
|
||||
let err = Error::Chat("timeout".to_string());
|
||||
assert_eq!(err.to_string(), "Chat error: timeout");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_unknown_permission_request() {
|
||||
let err = Error::UnknownPermissionRequest("req-99".to_string());
|
||||
assert_eq!(err.to_string(), "Unknown permission request: req-99");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_init_error() {
|
||||
let err = Error::Init("CRDT not ready".to_string());
|
||||
assert_eq!(err.to_string(), "Initialisation error: CRDT not ready");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_client_gone() {
|
||||
let err = Error::ClientGone;
|
||||
assert_eq!(err.to_string(), "Client disconnected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_is_debug() {
|
||||
let err = Error::InvalidMessage("test".to_string());
|
||||
let debug = format!("{err:?}");
|
||||
assert!(debug.contains("InvalidMessage"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants_display_without_panic() {
|
||||
let variants: Vec<Error> = vec![
|
||||
Error::InvalidMessage("a".to_string()),
|
||||
Error::Chat("b".to_string()),
|
||||
Error::UnknownPermissionRequest("c".to_string()),
|
||||
Error::Init("d".to_string()),
|
||||
Error::ClientGone,
|
||||
];
|
||||
for v in &variants {
|
||||
let _ = v.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user