fixes
This commit is contained in:
31
CONTEXT.md
31
CONTEXT.md
@@ -357,7 +357,23 @@ reaction_other = "gray"
|
||||
- Проще добавлять новые фичи
|
||||
- Лучше читаемость
|
||||
|
||||
**Следующие шаги**: Priority 2 (типобезопасность: Error enum, Newtype для ID)
|
||||
**Priority 2 (40% завершено - 2/5)**:
|
||||
- ✅ **P2.5 — Error enum** (завершено 2026-01-31)
|
||||
- Создан `src/error.rs` с типобезопасным enum `TeletuiError`
|
||||
- Добавлены варианты: TdLib, Config, Network, Auth, Chat, Message, User, InvalidTimezone, InvalidColor, Clipboard, Io, Toml, Json, Other
|
||||
- Type alias `Result<T>` для упрощения сигнатур
|
||||
- Использован `thiserror` для автоматического Display
|
||||
- Заменены все `Result<T, String>` на `Result<T>` в 7 модулях
|
||||
- Все 350 тестов проходят ✅
|
||||
|
||||
- ✅ **P2.3 — Config validation** (завершено 2026-01-31)
|
||||
- Добавлен метод `Config::validate()` для проверки конфигурации
|
||||
- Валидация timezone: проверка что начинается с + или -
|
||||
- Валидация цветов: проверка что цвет из списка допустимых (black, red, green, yellow, blue, magenta, cyan, gray, white, darkgray, lightred, lightgreen, lightyellow, lightblue, lightmagenta, lightcyan)
|
||||
- При загрузке невалидного конфига автоматически используется дефолтный
|
||||
- Все 350 тестов проходят ✅
|
||||
|
||||
**Следующие шаги**: Priority 2 (Newtype для ID, MessageBuilder, реструктуризация MessageInfo)
|
||||
|
||||
Подробности: [REFACTORING_ROADMAP.md](REFACTORING_ROADMAP.md)
|
||||
|
||||
@@ -374,11 +390,16 @@ reaction_other = "gray"
|
||||
2. ~~**Разделение TdClient**~~ ✅ — разделён на 7 модулей
|
||||
3. ~~**Константы**~~ ✅ — вынесены в отдельный модуль
|
||||
|
||||
**Завершено** (Priority 2):
|
||||
1. ~~**Error enum**~~ ✅ — типобезопасная обработка ошибок (2026-01-31)
|
||||
2. ~~**Config validation**~~ ✅ — валидация конфигурации при загрузке (2026-01-31)
|
||||
|
||||
**В работе** (Priority 2-5):
|
||||
1. **Типобезопасность** — newtype pattern для ID, error enum
|
||||
2. **UI компоненты** — выделить переиспользуемые компоненты
|
||||
3. **Форматирование** — вынести markdown форматирование в отдельный модуль
|
||||
4. **Юнит-тесты** — добавить для utils и других модулей
|
||||
1. **Типобезопасность** — newtype pattern для ID
|
||||
2. **MessageBuilder** — упрощение создания сообщений
|
||||
3. **UI компоненты** — выделить переиспользуемые компоненты
|
||||
4. **Форматирование** — вынести markdown форматирование в отдельный модуль
|
||||
5. **Юнит-тесты** — добавить для utils и других модулей
|
||||
|
||||
## Известные проблемы
|
||||
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2237,6 +2237,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tdlib-rs",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-test",
|
||||
"toml",
|
||||
|
||||
@@ -22,6 +22,7 @@ open = "5.0"
|
||||
arboard = "3.4"
|
||||
toml = "0.8"
|
||||
dirs = "5.0"
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
insta = "1.34"
|
||||
|
||||
@@ -608,12 +608,12 @@ tracing-subscriber = "0.3"
|
||||
- [x] P1.1 — ChatState enum
|
||||
- [x] P1.2 — Разделить TdClient
|
||||
- [x] P1.3 — Константы
|
||||
- [ ] Priority 2: 0/3 задач
|
||||
- [x] Priority 2: 2/5 задач (40%)
|
||||
- [ ] Priority 3: 0/4 задач
|
||||
- [ ] Priority 4: 0/4 задач
|
||||
- [ ] Priority 5: 0/3 задач
|
||||
|
||||
**Всего**: 3/17 задач (18%)
|
||||
**Всего**: 5/17 задач (29%)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
101
src/error.rs
Normal 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,
|
||||
}
|
||||
Reference in New Issue
Block a user