|
| 1 | +//! core crate 统一错误类型。 |
| 2 | +
|
| 3 | +use std::path::PathBuf; |
| 4 | + |
| 5 | +use thiserror::Error; |
| 6 | + |
| 7 | +/// 持久化层错误。 |
| 8 | +#[derive(Debug, Error)] |
| 9 | +pub enum PersistError { |
| 10 | + /// 系统数据目录不可用。 |
| 11 | + #[error("cannot determine system data directory")] |
| 12 | + SystemDataDirUnavailable, |
| 13 | + /// 路径 I/O 错误。 |
| 14 | + #[error("{op} `{path}` failed: {source}")] |
| 15 | + PathIo { |
| 16 | + op: &'static str, |
| 17 | + path: PathBuf, |
| 18 | + #[source] |
| 19 | + source: std::io::Error, |
| 20 | + }, |
| 21 | + /// 密钥文件长度非法。 |
| 22 | + #[error("invalid key file length: expected {expected} bytes, got {actual} bytes")] |
| 23 | + InvalidKeyLength { expected: usize, actual: usize }, |
| 24 | + /// profile 解析失败。 |
| 25 | + #[cfg(feature = "persist")] |
| 26 | + #[error("failed to parse profile `{path}`: {source}")] |
| 27 | + ProfileParse { |
| 28 | + path: PathBuf, |
| 29 | + #[source] |
| 30 | + source: toml::de::Error, |
| 31 | + }, |
| 32 | + /// profile 序列化失败。 |
| 33 | + #[cfg(feature = "persist")] |
| 34 | + #[error(transparent)] |
| 35 | + ProfileSerialize(#[from] toml::ser::Error), |
| 36 | + /// relay URL 解析失败。 |
| 37 | + #[error("invalid relay URL: {0}")] |
| 38 | + RelayUrlParse(String), |
| 39 | +} |
| 40 | + |
| 41 | +/// 票据解析错误。 |
| 42 | +#[derive(Debug, Error)] |
| 43 | +pub enum TicketError { |
| 44 | + /// URL 解析失败。 |
| 45 | + #[error(transparent)] |
| 46 | + UrlParse(#[from] url::ParseError), |
| 47 | + /// 协议不匹配。 |
| 48 | + #[error("invalid scheme: expected \"{expected}\", got \"{actual}\"")] |
| 49 | + InvalidScheme { |
| 50 | + expected: &'static str, |
| 51 | + actual: String, |
| 52 | + }, |
| 53 | + /// 缺少 endpoint id。 |
| 54 | + #[error("missing endpoint id in ticket URL")] |
| 55 | + MissingEndpointId, |
| 56 | + /// endpoint id 非法。 |
| 57 | + #[error("invalid endpoint id: {0}")] |
| 58 | + EndpointIdParse(String), |
| 59 | + /// relay URL 非法。 |
| 60 | + #[error("invalid relay URL: {0}")] |
| 61 | + RelayUrlParse(String), |
| 62 | +} |
| 63 | + |
| 64 | +/// 隧道运行时错误。 |
| 65 | +#[derive(Debug, Error)] |
| 66 | +pub enum TunnelError { |
| 67 | + /// 锁中毒。 |
| 68 | + #[error("mutex poisoned: {name}")] |
| 69 | + MutexPoisoned { name: &'static str }, |
| 70 | + /// 绑定 host endpoint 失败。 |
| 71 | + #[error("bind host endpoint failed: {0}")] |
| 72 | + BindHostEndpoint(String), |
| 73 | + /// 绑定 join endpoint 失败。 |
| 74 | + #[error("bind join endpoint failed: {0}")] |
| 75 | + BindJoinEndpoint(String), |
| 76 | + /// 绑定本地 TCP 监听失败。 |
| 77 | + #[error("bind local tcp listener failed: {0}")] |
| 78 | + BindLocalListener(String), |
| 79 | + /// host accept 失败。 |
| 80 | + #[error("accept host connection failed: {0}")] |
| 81 | + AcceptHostConnection(String), |
| 82 | + /// QUIC 双向流 accept 失败。 |
| 83 | + #[error("accept QUIC bi stream failed: {0}")] |
| 84 | + AcceptQuicBiStream(String), |
| 85 | + /// 本地 TCP 客户端 accept 失败。 |
| 86 | + #[error("accept local tcp client failed: {0}")] |
| 87 | + AcceptLocalTcpClient(String), |
| 88 | + /// 与 host 建连失败。 |
| 89 | + #[error("connect host endpoint failed: {0}")] |
| 90 | + ConnectHostEndpoint(String), |
| 91 | + /// 初次连接重试耗尽。 |
| 92 | + #[error("initial connection failed after {attempts} attempts")] |
| 93 | + InitialConnectionExhausted { attempts: u32 }, |
| 94 | + /// 打开认证流失败。 |
| 95 | + #[error("open auth stream failed: {0}")] |
| 96 | + OpenAuthStream(String), |
| 97 | + /// 接收认证流失败。 |
| 98 | + #[error("accept auth stream failed: {0}")] |
| 99 | + AcceptAuthStream(String), |
| 100 | + /// 读取认证结果失败。 |
| 101 | + #[error("read auth result failed: {0}")] |
| 102 | + ReadAuthResult(String), |
| 103 | + /// 读取认证负载失败。 |
| 104 | + #[error("read auth payload failed: {0}")] |
| 105 | + ReadAuthPayload(String), |
| 106 | + /// 写入认证负载失败。 |
| 107 | + #[error("write auth payload failed: {0}")] |
| 108 | + WriteAuthPayload(String), |
| 109 | + /// 写入认证拒绝失败。 |
| 110 | + #[error("write auth rejected failed: {0}")] |
| 111 | + WriteAuthRejected(String), |
| 112 | + /// 写入认证决策失败。 |
| 113 | + #[error("write auth decision failed: {0}")] |
| 114 | + WriteAuthDecision(String), |
| 115 | + /// 结束认证流失败。 |
| 116 | + #[error("finish auth stream failed: {0}")] |
| 117 | + FinishAuthStream(String), |
| 118 | + /// 认证被 host 拒绝。 |
| 119 | + #[error("auth rejected by host")] |
| 120 | + AuthRejectedByHost, |
| 121 | + /// 桥接 tcp->quic 失败。 |
| 122 | + #[error("bridge tcp->quic failed: {0}")] |
| 123 | + BridgeTcpToQuic(String), |
| 124 | + /// 桥接 quic->tcp 失败。 |
| 125 | + #[error("bridge quic->tcp failed: {0}")] |
| 126 | + BridgeQuicToTcp(String), |
| 127 | +} |
| 128 | + |
| 129 | +/// sculk core 顶层错误。 |
| 130 | +#[derive(Debug, Error)] |
| 131 | +pub enum SculkError { |
| 132 | + /// 持久化错误。 |
| 133 | + #[error(transparent)] |
| 134 | + Persist(#[from] PersistError), |
| 135 | + /// 票据错误。 |
| 136 | + #[error(transparent)] |
| 137 | + Ticket(#[from] TicketError), |
| 138 | + /// 隧道错误。 |
| 139 | + #[error(transparent)] |
| 140 | + Tunnel(#[from] TunnelError), |
| 141 | +} |
| 142 | + |
| 143 | +impl TunnelError { |
| 144 | + /// 构造锁中毒错误。 |
| 145 | + pub fn mutex_poisoned(name: &'static str) -> Self { |
| 146 | + Self::MutexPoisoned { name } |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | +/// core crate 统一 `Result` 别名。 |
| 151 | +pub type Result<T> = std::result::Result<T, SculkError>; |
0 commit comments