-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror_codes.rs
More file actions
221 lines (201 loc) · 8.4 KB
/
Copy patherror_codes.rs
File metadata and controls
221 lines (201 loc) · 8.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! Unified error model for CLI
//! Provides structured error codes and messages for consistent error handling
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ErrorCode {
// External/stable codes (guaranteed in CLI responses)
AliasExists,
AliasNotFound,
VaultLocked,
NoActiveProfile,
InvalidInput,
UnknownError,
UnsupportedProtocol,
InternalError,
// Internal codes
Unauthorized,
Forbidden,
IoError,
Timeout,
VaultNotInitialized,
ProfileNotFound,
// ===== `_internal` IPC 错误码(I_ 前缀)=====
// 用于 `aikey _internal *` 子命令组的 stdin-json 协议。
// 这些错误码通过 stdout JSON 返回给 Go local-server(不是 exit code)。
// 新增时:同步更新 as_str() / code() 映射 + docs/VAULT_SPEC.md 错误码表。
InternalStdinInvalidJson, // I_STDIN_INVALID_JSON
InternalStdinReadFailed, // I_STDIN_READ_FAILED
InternalVaultKeyMalformed, // I_VAULT_KEY_MALFORMED(hex 长度/格式错)
InternalVaultKeyInvalid, // I_VAULT_KEY_INVALID(key 不匹配 vault)
InternalVaultNotInitialized, // I_VAULT_NOT_INITIALIZED
InternalVaultOpenFailed, // I_VAULT_OPEN_FAILED
InternalUnknownAction, // I_UNKNOWN_ACTION(envelope.action 不认识)
InternalNotImplemented, // I_NOT_IMPLEMENTED(Phase 占位)
InternalCredentialNotFound, // I_CREDENTIAL_NOT_FOUND
InternalCredentialConflict, // I_CREDENTIAL_CONFLICT(add 时 alias 已存在)
InternalParseFailed, // I_PARSE_FAILED(解析引擎三层流水失败)
InternalIo, // I_INTERNAL(serialize/io 等意外内部错误)
}
impl ErrorCode {
pub fn as_str(&self) -> &'static str {
match self {
ErrorCode::AliasExists => "ALIAS_EXISTS",
ErrorCode::AliasNotFound => "ALIAS_NOT_FOUND",
ErrorCode::VaultLocked => "VAULT_LOCKED",
ErrorCode::NoActiveProfile => "NO_ACTIVE_PROFILE",
ErrorCode::InvalidInput => "INVALID_INPUT",
ErrorCode::UnknownError => "UNKNOWN_ERROR",
ErrorCode::UnsupportedProtocol => "UNSUPPORTED_PROTOCOL",
ErrorCode::InternalError => "INTERNAL_ERROR",
ErrorCode::Unauthorized => "UNAUTHORIZED",
ErrorCode::Forbidden => "FORBIDDEN",
ErrorCode::IoError => "IO_ERROR",
ErrorCode::Timeout => "TIMEOUT",
ErrorCode::VaultNotInitialized => "VAULT_NOT_INITIALIZED",
ErrorCode::ProfileNotFound => "PROFILE_NOT_FOUND",
// _internal IPC 错误码
ErrorCode::InternalStdinInvalidJson => "I_STDIN_INVALID_JSON",
ErrorCode::InternalStdinReadFailed => "I_STDIN_READ_FAILED",
ErrorCode::InternalVaultKeyMalformed => "I_VAULT_KEY_MALFORMED",
ErrorCode::InternalVaultKeyInvalid => "I_VAULT_KEY_INVALID",
ErrorCode::InternalVaultNotInitialized => "I_VAULT_NOT_INITIALIZED",
ErrorCode::InternalVaultOpenFailed => "I_VAULT_OPEN_FAILED",
ErrorCode::InternalUnknownAction => "I_UNKNOWN_ACTION",
ErrorCode::InternalNotImplemented => "I_NOT_IMPLEMENTED",
ErrorCode::InternalCredentialNotFound => "I_CREDENTIAL_NOT_FOUND",
ErrorCode::InternalCredentialConflict => "I_CREDENTIAL_CONFLICT",
ErrorCode::InternalParseFailed => "I_PARSE_FAILED",
ErrorCode::InternalIo => "I_INTERNAL",
}
}
pub fn code(&self) -> i32 {
match self {
ErrorCode::AliasExists => 1001,
ErrorCode::AliasNotFound => 1002,
ErrorCode::VaultLocked => 1003,
ErrorCode::NoActiveProfile => 1004,
ErrorCode::InvalidInput => 1005,
ErrorCode::UnknownError => 1006,
ErrorCode::UnsupportedProtocol => -32001,
ErrorCode::InternalError => -32603,
ErrorCode::Unauthorized => -32002,
ErrorCode::Forbidden => -32003,
ErrorCode::IoError => -32004,
ErrorCode::Timeout => -32005,
ErrorCode::VaultNotInitialized => -32006,
ErrorCode::ProfileNotFound => -32007,
// _internal IPC: 负数区间(与其他 internal 保持一致)
ErrorCode::InternalStdinInvalidJson => -32101,
ErrorCode::InternalStdinReadFailed => -32102,
ErrorCode::InternalVaultKeyMalformed => -32103,
ErrorCode::InternalVaultKeyInvalid => -32104,
ErrorCode::InternalVaultNotInitialized => -32105,
ErrorCode::InternalVaultOpenFailed => -32106,
ErrorCode::InternalUnknownAction => -32107,
ErrorCode::InternalNotImplemented => -32108,
ErrorCode::InternalCredentialNotFound => -32109,
ErrorCode::InternalCredentialConflict => -32110,
ErrorCode::InternalParseFailed => -32111,
ErrorCode::InternalIo => -32199,
}
}
/// Map internal error messages to error codes
pub fn from_error_message(msg: &str) -> Self {
if msg.contains("already exists") || msg.contains("duplicate") {
ErrorCode::AliasExists
} else if msg.contains("not found") || msg.contains("does not exist") {
ErrorCode::AliasNotFound
} else if msg.contains("password")
|| msg.contains("authentication")
|| msg.contains("locked")
{
ErrorCode::VaultLocked
} else if msg.contains("profile") {
ErrorCode::NoActiveProfile
} else if msg.contains("invalid") {
ErrorCode::InvalidInput
} else {
ErrorCode::UnknownError
}
}
}
/// Centralized user-facing message templates.
/// Use these constants instead of hardcoding strings at call sites.
pub mod msgs {
pub const NO_CONFIG_FOUND: &str =
"No aikey.config.json found. Run 'aikey project init' to create one.";
pub const NO_CONFIG_FOUND_HINT: &str =
"No aikey.config.json found. Run 'aikey project init' to create one, or use --provider to specify a provider directly.";
pub const NO_CONFIG_FOUND_DIR: &str =
"No aikey.config.json found in current directory or parent directories";
pub const NO_PROJECT_CONFIG: &str =
"No project configuration found. Run 'aikey project init' first.";
pub const INVALID_PASSWORD: &str = "Invalid master password or corrupted vault.";
pub const INVALID_PASSWORD_SHORT: &str = "Invalid master password.";
}
/// Unified error type for CLI
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Error {
pub code: ErrorCode,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub details: Option<serde_json::Value>,
}
impl Error {
pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
details: None,
}
}
pub fn with_details(mut self, details: serde_json::Value) -> Self {
self.details = Some(details);
self
}
pub fn alias_exists(name: &str) -> Self {
Self::new(
ErrorCode::AliasExists,
format!("Secret already exists: {}", name),
)
}
pub fn alias_not_found(name: &str) -> Self {
Self::new(
ErrorCode::AliasNotFound,
format!("Secret not found: {}", name),
)
}
pub fn vault_locked() -> Self {
Self::new(
ErrorCode::VaultLocked,
"Vault is locked or password is incorrect",
)
}
pub fn no_active_profile() -> Self {
Self::new(
ErrorCode::NoActiveProfile,
"No active profile is configured",
)
}
pub fn invalid_input(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::InvalidInput, msg)
}
pub fn unknown_error(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::UnknownError, msg)
}
pub fn vault_not_initialized() -> Self {
Self::new(
ErrorCode::VaultNotInitialized,
"Vault not initialized. Run any aikey command to initialize it automatically.",
)
}
pub fn profile_not_found(name: &str) -> Self {
Self::new(
ErrorCode::ProfileNotFound,
format!("Profile not found: {}", name),
)
}
pub fn internal_error(msg: impl Into<String>) -> Self {
Self::new(ErrorCode::InternalError, msg)
}
}