mcpkit_core/error/
transport.rs

1//! Transport error types and context.
2//!
3//! This module provides classification and contextual information
4//! for transport-level errors.
5
6use std::fmt;
7
8use serde::{Deserialize, Serialize};
9
10/// Classification of transport errors.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(rename_all = "snake_case")]
13pub enum TransportErrorKind {
14    /// Connection could not be established.
15    ConnectionFailed,
16    /// Connection was closed unexpectedly.
17    ConnectionClosed,
18    /// Read operation failed.
19    ReadFailed,
20    /// Write operation failed.
21    WriteFailed,
22    /// TLS/SSL error occurred.
23    TlsError,
24    /// DNS resolution failed.
25    DnsResolutionFailed,
26    /// Operation timed out.
27    Timeout,
28    /// Message format was invalid.
29    InvalidMessage,
30    /// Protocol violation detected.
31    ProtocolViolation,
32    /// Resources exhausted (e.g., too many connections).
33    ResourceExhausted,
34    /// Rate limit exceeded.
35    RateLimited,
36}
37
38impl fmt::Display for TransportErrorKind {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            Self::ConnectionFailed => write!(f, "connection failed"),
42            Self::ConnectionClosed => write!(f, "connection closed"),
43            Self::ReadFailed => write!(f, "read failed"),
44            Self::WriteFailed => write!(f, "write failed"),
45            Self::TlsError => write!(f, "TLS error"),
46            Self::DnsResolutionFailed => write!(f, "DNS resolution failed"),
47            Self::Timeout => write!(f, "timeout"),
48            Self::InvalidMessage => write!(f, "invalid message"),
49            Self::ProtocolViolation => write!(f, "protocol violation"),
50            Self::ResourceExhausted => write!(f, "resource exhausted"),
51            Self::RateLimited => write!(f, "rate limited"),
52        }
53    }
54}
55
56/// Additional context for transport errors.
57#[derive(Debug, Clone, Default, Serialize, Deserialize)]
58pub struct TransportContext {
59    /// Transport type (stdio, http, websocket, unix).
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub transport_type: Option<String>,
62    /// Remote endpoint address.
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub remote_addr: Option<String>,
65    /// Local endpoint address.
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub local_addr: Option<String>,
68    /// Bytes sent before error occurred.
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub bytes_sent: Option<u64>,
71    /// Bytes received before error occurred.
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub bytes_received: Option<u64>,
74    /// Connection duration before error.
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub connection_duration_ms: Option<u64>,
77}
78
79impl TransportContext {
80    /// Create a new transport context for a specific transport type.
81    #[must_use]
82    pub fn new(transport_type: impl Into<String>) -> Self {
83        Self {
84            transport_type: Some(transport_type.into()),
85            ..Default::default()
86        }
87    }
88
89    /// Set the remote address.
90    #[must_use]
91    pub fn with_remote_addr(mut self, addr: impl Into<String>) -> Self {
92        self.remote_addr = Some(addr.into());
93        self
94    }
95
96    /// Set the local address.
97    #[must_use]
98    pub fn with_local_addr(mut self, addr: impl Into<String>) -> Self {
99        self.local_addr = Some(addr.into());
100        self
101    }
102}