This commit is contained in:
Mikhail Kilin
2026-01-31 01:00:43 +03:00
parent bba5cbd22d
commit 38e73befc1
6 changed files with 188 additions and 8 deletions

View File

@@ -93,6 +93,53 @@ impl Default for Config {
}
impl Config {
/// Валидация конфигурации
pub fn validate(&self) -> Result<(), String> {
// Проверка timezone
if !self.general.timezone.starts_with('+') && !self.general.timezone.starts_with('-') {
return Err(format!(
"Invalid timezone (must start with + or -): {}",
self.general.timezone
));
}
// Проверка цветов
let valid_colors = [
"black",
"red",
"green",
"yellow",
"blue",
"magenta",
"cyan",
"gray",
"grey",
"white",
"darkgray",
"darkgrey",
"lightred",
"lightgreen",
"lightyellow",
"lightblue",
"lightmagenta",
"lightcyan",
];
for color_name in [
&self.colors.incoming_message,
&self.colors.outgoing_message,
&self.colors.selected_message,
&self.colors.reaction_chosen,
&self.colors.reaction_other,
] {
if !valid_colors.contains(&color_name.to_lowercase().as_str()) {
return Err(format!("Invalid color: {}", color_name));
}
}
Ok(())
}
/// Путь к конфигурационному файлу
pub fn config_path() -> Option<PathBuf> {
dirs::config_dir().map(|mut path| {
@@ -131,7 +178,16 @@ impl Config {
match fs::read_to_string(&config_path) {
Ok(content) => match toml::from_str::<Config>(&content) {
Ok(config) => config,
Ok(config) => {
// Валидируем загруженный конфиг
if let Err(e) = config.validate() {
eprintln!("Config validation error: {}", e);
eprintln!("Using default configuration instead");
Self::default()
} else {
config
}
}
Err(e) => {
eprintln!("Warning: Could not parse config file: {}", e);
Self::default()

101
src/error.rs Normal file
View File

@@ -0,0 +1,101 @@
/// Error types for tele-tui application
///
/// Provides type-safe error handling across the application,
/// replacing generic String errors with structured variants.
#[derive(Debug, thiserror::Error)]
pub enum TeletuiError {
/// TDLib-related errors
#[error("TDLib error: {0}")]
TdLib(String),
/// Configuration errors
#[error("Configuration error: {0}")]
Config(String),
/// Network connectivity errors
#[error("Network error: {0}")]
Network(String),
/// Authentication errors
#[error("Authentication error: {0}")]
Auth(String),
/// Invalid timezone format
#[error("Invalid timezone format: {0}")]
InvalidTimezone(String),
/// Invalid color value
#[error("Invalid color: {0}")]
InvalidColor(String),
/// Message operation errors
#[error("Message error: {0}")]
Message(String),
/// Chat operation errors
#[error("Chat error: {0}")]
Chat(String),
/// User operation errors
#[error("User error: {0}")]
User(String),
/// File system errors
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
/// TOML parsing errors
#[error("TOML error: {0}")]
Toml(#[from] toml::de::Error),
/// JSON parsing errors
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
/// Clipboard errors
#[error("Clipboard error: {0}")]
Clipboard(String),
/// Generic error for cases not covered by specific variants
#[error("{0}")]
Other(String),
}
/// Result type alias using TeletuiError
pub type Result<T> = std::result::Result<T, TeletuiError>;
/// Helper trait for converting String errors to TeletuiError
pub trait IntoTeletuiError {
fn into_teletui_error(self, variant: ErrorVariant) -> TeletuiError;
}
impl IntoTeletuiError for String {
fn into_teletui_error(self, variant: ErrorVariant) -> TeletuiError {
match variant {
ErrorVariant::TdLib => TeletuiError::TdLib(self),
ErrorVariant::Config => TeletuiError::Config(self),
ErrorVariant::Network => TeletuiError::Network(self),
ErrorVariant::Auth => TeletuiError::Auth(self),
ErrorVariant::Message => TeletuiError::Message(self),
ErrorVariant::Chat => TeletuiError::Chat(self),
ErrorVariant::User => TeletuiError::User(self),
ErrorVariant::Clipboard => TeletuiError::Clipboard(self),
ErrorVariant::Other => TeletuiError::Other(self),
}
}
}
/// Error variant selector for conversion
#[derive(Debug, Clone, Copy)]
pub enum ErrorVariant {
TdLib,
Config,
Network,
Auth,
Message,
Chat,
User,
Clipboard,
Other,
}