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)
|
Подробности: [REFACTORING_ROADMAP.md](REFACTORING_ROADMAP.md)
|
||||||
|
|
||||||
@@ -374,11 +390,16 @@ reaction_other = "gray"
|
|||||||
2. ~~**Разделение TdClient**~~ ✅ — разделён на 7 модулей
|
2. ~~**Разделение TdClient**~~ ✅ — разделён на 7 модулей
|
||||||
3. ~~**Константы**~~ ✅ — вынесены в отдельный модуль
|
3. ~~**Константы**~~ ✅ — вынесены в отдельный модуль
|
||||||
|
|
||||||
|
**Завершено** (Priority 2):
|
||||||
|
1. ~~**Error enum**~~ ✅ — типобезопасная обработка ошибок (2026-01-31)
|
||||||
|
2. ~~**Config validation**~~ ✅ — валидация конфигурации при загрузке (2026-01-31)
|
||||||
|
|
||||||
**В работе** (Priority 2-5):
|
**В работе** (Priority 2-5):
|
||||||
1. **Типобезопасность** — newtype pattern для ID, error enum
|
1. **Типобезопасность** — newtype pattern для ID
|
||||||
2. **UI компоненты** — выделить переиспользуемые компоненты
|
2. **MessageBuilder** — упрощение создания сообщений
|
||||||
3. **Форматирование** — вынести markdown форматирование в отдельный модуль
|
3. **UI компоненты** — выделить переиспользуемые компоненты
|
||||||
4. **Юнит-тесты** — добавить для utils и других модулей
|
4. **Форматирование** — вынести markdown форматирование в отдельный модуль
|
||||||
|
5. **Юнит-тесты** — добавить для utils и других модулей
|
||||||
|
|
||||||
## Известные проблемы
|
## Известные проблемы
|
||||||
|
|
||||||
|
|||||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2237,6 +2237,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tdlib-rs",
|
"tdlib-rs",
|
||||||
|
"thiserror 1.0.69",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-test",
|
"tokio-test",
|
||||||
"toml",
|
"toml",
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ open = "5.0"
|
|||||||
arboard = "3.4"
|
arboard = "3.4"
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
dirs = "5.0"
|
dirs = "5.0"
|
||||||
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
insta = "1.34"
|
insta = "1.34"
|
||||||
|
|||||||
@@ -608,12 +608,12 @@ tracing-subscriber = "0.3"
|
|||||||
- [x] P1.1 — ChatState enum
|
- [x] P1.1 — ChatState enum
|
||||||
- [x] P1.2 — Разделить TdClient
|
- [x] P1.2 — Разделить TdClient
|
||||||
- [x] P1.3 — Константы
|
- [x] P1.3 — Константы
|
||||||
- [ ] Priority 2: 0/3 задач
|
- [x] Priority 2: 2/5 задач (40%)
|
||||||
- [ ] Priority 3: 0/4 задач
|
- [ ] Priority 3: 0/4 задач
|
||||||
- [ ] Priority 4: 0/4 задач
|
- [ ] Priority 4: 0/4 задач
|
||||||
- [ ] Priority 5: 0/3 задач
|
- [ ] Priority 5: 0/3 задач
|
||||||
|
|
||||||
**Всего**: 3/17 задач (18%)
|
**Всего**: 5/17 задач (29%)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,53 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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> {
|
pub fn config_path() -> Option<PathBuf> {
|
||||||
dirs::config_dir().map(|mut path| {
|
dirs::config_dir().map(|mut path| {
|
||||||
@@ -131,7 +178,16 @@ impl Config {
|
|||||||
|
|
||||||
match fs::read_to_string(&config_path) {
|
match fs::read_to_string(&config_path) {
|
||||||
Ok(content) => match toml::from_str::<Config>(&content) {
|
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) => {
|
Err(e) => {
|
||||||
eprintln!("Warning: Could not parse config file: {}", e);
|
eprintln!("Warning: Could not parse config file: {}", e);
|
||||||
Self::default()
|
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