Split monolithic files into modular architecture: - ui/messages.rs (893→365 lines): extract modals/, compose_bar.rs - tdlib/messages.rs (836→3 files): split into messages/mod, convert, operations - config/mod.rs (642→3 files): extract validation.rs, loader.rs - Code duplication cleanup: shared components, ~220 lines removed - Documentation: PROJECT_STRUCTURE.md rewrite, 16 files got //! docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
329 lines
18 KiB
Markdown
329 lines
18 KiB
Markdown
# Структура проекта
|
||
|
||
## Архитектура (ASCII)
|
||
|
||
```
|
||
┌─────────────┐
|
||
│ main.rs │ Event loop (60 FPS)
|
||
└──────┬──────┘
|
||
│
|
||
┌────────────┼────────────┐
|
||
▼ ▼ ▼
|
||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||
│ input/ │ │ app/ │ │ ui/ │
|
||
│ handlers │ │ state │ │ render │
|
||
└────┬─────┘ └────┬─────┘ └────┬─────┘
|
||
│ │ │
|
||
│ ┌──────┴──────┐ │
|
||
│ │ methods/ │ │
|
||
│ │ (5 traits) │ │
|
||
│ └──────┬──────┘ │
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌─────────────────────────────────┐
|
||
│ tdlib/ │
|
||
│ TdClientTrait → TdClient │
|
||
│ messages/ | auth | chats │
|
||
└──────────────┬──────────────────┘
|
||
│
|
||
┌─────▼─────┐
|
||
│ TDLib C │
|
||
│ library │
|
||
└───────────┘
|
||
```
|
||
|
||
### Data Flow
|
||
```
|
||
TDLib Updates → mpsc channel → App state → UI rendering
|
||
User Input → handlers → App methods (traits) → TdClient → TDLib API
|
||
```
|
||
|
||
## Обзор директорий
|
||
|
||
```
|
||
tele-tui/
|
||
├── src/
|
||
│ ├── main.rs # Точка входа, event loop
|
||
│ ├── lib.rs # Экспорт модулей для тестов
|
||
│ ├── types.rs # ChatId, MessageId (newtype wrappers)
|
||
│ ├── constants.rs # MAX_MESSAGES_IN_CHAT, etc.
|
||
│ ├── formatting.rs # Markdown entity форматирование
|
||
│ ├── message_grouping.rs # Группировка сообщений по дате/отправителю
|
||
│ ├── notifications.rs # Desktop уведомления (NotificationManager)
|
||
│ │
|
||
│ ├── app/ # Состояние приложения
|
||
│ │ ├── mod.rs # App<T> struct, конструкторы, getters (372 loc)
|
||
│ │ ├── state.rs # AppScreen enum
|
||
│ │ ├── chat_state.rs # ChatState enum (state machine)
|
||
│ │ ├── chat_filter.rs # ChatFilter, ChatFilterCriteria
|
||
│ │ ├── chat_list_state.rs # Состояние списка чатов
|
||
│ │ ├── auth_state.rs # Состояние авторизации
|
||
│ │ ├── compose_state.rs # Состояние compose bar
|
||
│ │ ├── ui_state.rs # UI-related state
|
||
│ │ ├── message_service.rs # Сервис сообщений
|
||
│ │ ├── message_view_state.rs # Состояние просмотра сообщений
|
||
│ │ └── methods/ # Trait-based методы App (Этап 2)
|
||
│ │ ├── mod.rs # Re-exports 5 trait модулей
|
||
│ │ ├── navigation.rs # NavigationMethods (7 методов)
|
||
│ │ ├── messages.rs # MessageMethods (8 методов)
|
||
│ │ ├── compose.rs # ComposeMethods (10 методов)
|
||
│ │ ├── search.rs # SearchMethods (15 методов)
|
||
│ │ └── modal.rs # ModalMethods (27 методов)
|
||
│ │
|
||
│ ├── config/ # Конфигурация (Этап 5)
|
||
│ │ ├── mod.rs # Config struct, defaults (350 loc)
|
||
│ │ ├── keybindings.rs # Command enum, Keybindings
|
||
│ │ ├── validation.rs # validate(), parse_color()
|
||
│ │ └── loader.rs # load(), save(), credentials
|
||
│ │
|
||
│ ├── input/ # Обработка пользовательского ввода
|
||
│ │ ├── mod.rs # Роутинг по экранам
|
||
│ │ ├── auth.rs # Ввод на экране авторизации
|
||
│ │ ├── main_input.rs # Роутер главного экрана (159 loc, Этап 1)
|
||
│ │ ├── key_handler.rs # Trait-based обработка клавиш
|
||
│ │ └── handlers/ # Специализированные обработчики (Этап 1)
|
||
│ │ ├── mod.rs # Exports + scroll_to_message()
|
||
│ │ ├── global.rs # Ctrl+R/S/P/F глобальные команды
|
||
│ │ ├── chat.rs # Открытый чат: ввод, скролл, selection
|
||
│ │ ├── chat_list.rs # Навигация по списку чатов, папки
|
||
│ │ ├── compose.rs # Forward mode
|
||
│ │ ├── modal.rs # Profile, reactions, pinned, delete
|
||
│ │ ├── search.rs # Поиск чатов и сообщений
|
||
│ │ ├── clipboard.rs # Копирование в буфер обмена
|
||
│ │ └── profile.rs # Хелперы профиля
|
||
│ │
|
||
│ ├── tdlib/ # TDLib интеграция
|
||
│ │ ├── mod.rs # Экспорт публичных типов
|
||
│ │ ├── types.rs # MessageInfo, ChatInfo, ProfileInfo, etc.
|
||
│ │ ├── trait.rs # TdClientTrait (DI для тестов)
|
||
│ │ ├── client.rs # TdClient struct, конструктор
|
||
│ │ ├── client_impl.rs # impl TdClientTrait for TdClient
|
||
│ │ ├── auth.rs # Авторизация (phone, code, 2FA)
|
||
│ │ ├── chats.rs # Загрузка чатов, папок
|
||
│ │ ├── users.rs # Кеш пользователей, статусы
|
||
│ │ ├── reactions.rs # ReactionInfo, toggle_reaction
|
||
│ │ ├── chat_helpers.rs # Вспомогательные функции чатов
|
||
│ │ ├── update_handlers.rs # Обработка TDLib update events
|
||
│ │ ├── message_converter.rs # Конвертация TDLib → MessageInfo
|
||
│ │ ├── message_conversion.rs # Доп. функции конвертации
|
||
│ │ └── messages/ # Менеджер сообщений (Этап 4)
|
||
│ │ ├── mod.rs # MessageManager struct (99 loc)
|
||
│ │ ├── convert.rs # convert_message, fetch_reply_info
|
||
│ │ └── operations.rs # 11 TDLib API операций (616 loc)
|
||
│ │
|
||
│ ├── ui/ # Рендеринг интерфейса
|
||
│ │ ├── mod.rs # render() — роутинг по экранам
|
||
│ │ ├── loading.rs # Экран загрузки
|
||
│ │ ├── auth.rs # Экран авторизации
|
||
│ │ ├── main_screen.rs # Главный экран + папки
|
||
│ │ ├── footer.rs # Футер с командами и статусом сети
|
||
│ │ ├── chat_list.rs # Список чатов + онлайн-статус
|
||
│ │ ├── messages.rs # Область сообщений (364 loc, Этап 3)
|
||
│ │ ├── compose_bar.rs # Multi-mode input box (Этап 3)
|
||
│ │ ├── profile.rs # Профиль пользователя/чата
|
||
│ │ ├── modals/ # Модальные окна (Этап 3)
|
||
│ │ │ ├── mod.rs # Re-exports
|
||
│ │ │ ├── delete_confirm.rs # Подтверждение удаления
|
||
│ │ │ ├── reaction_picker.rs # Выбор реакции
|
||
│ │ │ ├── search.rs # Поиск по сообщениям
|
||
│ │ │ └── pinned.rs # Закреплённые сообщения
|
||
│ │ └── components/ # Переиспользуемые UI компоненты (Этап 6)
|
||
│ │ ├── mod.rs # Re-exports
|
||
│ │ ├── modal.rs # render_modal(), render_delete_confirm
|
||
│ │ ├── input_field.rs # render_input_field()
|
||
│ │ ├── message_bubble.rs # render_message_bubble(), sender, date
|
||
│ │ ├── message_list.rs # render_message_item(), help_bar, scroll
|
||
│ │ ├── chat_list_item.rs # render_chat_list_item()
|
||
│ │ └── emoji_picker.rs # render_emoji_picker()
|
||
│ │
|
||
│ └── utils/ # Утилиты
|
||
│ ├── mod.rs # Exports, with_timeout helpers
|
||
│ ├── formatting.rs # format_timestamp, format_date, etc.
|
||
│ ├── tdlib.rs # disable_tdlib_logs (FFI)
|
||
│ ├── validation.rs # is_non_empty и др.
|
||
│ ├── modal_handler.rs # handle_yes_no для Y/N модалок
|
||
│ └── retry.rs # Retry утилиты
|
||
│
|
||
├── tests/ # Интеграционные тесты
|
||
│ ├── helpers/ # Тестовая инфраструктура
|
||
│ │ ├── mod.rs
|
||
│ │ ├── app_builder.rs # TestAppBuilder (fluent API)
|
||
│ │ ├── fake_tdclient.rs # FakeTdClient (мок TDLib)
|
||
│ │ ├── fake_tdclient_impl.rs # impl TdClientTrait for FakeTdClient
|
||
│ │ ├── test_data.rs # create_test_chat, TestMessageBuilder
|
||
│ │ └── snapshot_utils.rs # Snapshot testing хелперы
|
||
│ ├── input_navigation.rs # Тесты навигации клавиатурой
|
||
│ ├── chat_list.rs # Тесты списка чатов
|
||
│ ├── messages.rs # Тесты сообщений
|
||
│ ├── send_message.rs # Тесты отправки
|
||
│ ├── edit_message.rs # Тесты редактирования
|
||
│ ├── delete_message.rs # Тесты удаления
|
||
│ ├── reply_forward.rs # Тесты reply/forward
|
||
│ ├── reactions.rs # Тесты реакций
|
||
│ ├── search.rs # Тесты поиска
|
||
│ ├── modals.rs # Тесты модальных окон
|
||
│ ├── profile.rs # Тесты профиля
|
||
│ ├── navigation.rs # Тесты навигации
|
||
│ ├── drafts.rs # Тесты черновиков
|
||
│ ├── copy.rs # Тесты копирования
|
||
│ ├── screens.rs # Тесты экранов
|
||
│ ├── footer.rs # Тесты футера
|
||
│ ├── input_field.rs # Тесты поля ввода
|
||
│ ├── config.rs # Тесты конфигурации
|
||
│ ├── network_typing.rs # Тесты typing status
|
||
│ ├── e2e_smoke.rs # Smoke тесты
|
||
│ └── e2e_user_journey.rs # E2E user journey тесты
|
||
│
|
||
├── .github/ # GitHub конфигурация
|
||
│ ├── ISSUE_TEMPLATE/
|
||
│ ├── workflows/ci.yml
|
||
│ └── pull_request_template.md
|
||
│
|
||
├── Cargo.toml # Манифест проекта
|
||
├── Cargo.lock # Точные версии зависимостей
|
||
├── build.rs # Build script (TDLib)
|
||
├── rustfmt.toml # cargo fmt конфигурация
|
||
├── .editorconfig # Настройки IDE
|
||
├── .gitignore # Git ignore
|
||
│
|
||
├── config.toml.example # Пример конфигурации
|
||
├── credentials.example # Пример credentials
|
||
│
|
||
├── CLAUDE.md # Инструкции для AI
|
||
├── CONTEXT.md # Текущий статус
|
||
├── ROADMAP.md # План развития
|
||
├── DEVELOPMENT.md # Правила разработки
|
||
├── REQUIREMENTS.md # Требования
|
||
├── ARCHITECTURE.md # C4, sequence diagrams
|
||
├── PROJECT_STRUCTURE.md # Этот файл
|
||
├── E2E_TESTING.md # Гайд по тестированию
|
||
├── HOTKEYS.md # Горячие клавиши
|
||
├── CHANGELOG.md # История изменений
|
||
├── README.md # Главная документация
|
||
├── INSTALL.md # Установка
|
||
├── FAQ.md # FAQ
|
||
├── CONTRIBUTING.md # Гайд по контрибуции
|
||
├── SECURITY.md # Безопасность
|
||
└── LICENSE # MIT лицензия
|
||
```
|
||
|
||
## Ключевые модули
|
||
|
||
### app/ — Состояние приложения
|
||
|
||
`App<T: TdClientTrait>` — главная структура, параметризована trait'ом для DI.
|
||
|
||
**State machine** (`ChatState` enum):
|
||
```
|
||
Normal → MessageSelection → Editing
|
||
→ Reply
|
||
→ Forward
|
||
→ DeleteConfirmation
|
||
→ ReactionPicker
|
||
→ Profile
|
||
→ SearchInChat
|
||
→ PinnedMessages
|
||
```
|
||
|
||
**Trait-based methods** (5 traits на `App<T>`):
|
||
| Trait | Методы | Описание |
|
||
|-------|--------|----------|
|
||
| NavigationMethods | 7 | next/previous_chat, close_chat, select_current_chat |
|
||
| MessageMethods | 8 | is_editing, is_replying, get_selected_message, etc. |
|
||
| ComposeMethods | 10 | start_reply, cancel_editing, load_draft, etc. |
|
||
| SearchMethods | 15 | start_search, enter_message_search_mode, etc. |
|
||
| ModalMethods | 27 | enter_profile_mode, exit_pinned_mode, etc. |
|
||
|
||
### input/ — Обработка ввода
|
||
|
||
**Маршрутизация** (порядок приоритетов в `main_input.rs`):
|
||
1. Global commands (Ctrl+R/S/P/F)
|
||
2. Profile mode
|
||
3. Message search mode
|
||
4. Pinned messages mode
|
||
5. Reaction picker mode
|
||
6. Delete confirmation
|
||
7. Forward mode
|
||
8. Chat search mode
|
||
9. Enter/Esc commands
|
||
10. Open chat input / Chat list navigation
|
||
|
||
### tdlib/ — Telegram интеграция
|
||
|
||
**Dependency Injection**: `TdClientTrait` позволяет подменять TdClient на `FakeTdClient` в тестах.
|
||
|
||
**MessageManager** — управление сообщениями:
|
||
- `convert.rs` — конвертация TDLib JSON → MessageInfo
|
||
- `operations.rs` — 11 API операций (get_history, send, edit, delete, forward, search, etc.)
|
||
|
||
### ui/ — Рендеринг
|
||
|
||
**Компоненты** (`ui/components/`):
|
||
| Компонент | Описание |
|
||
|-----------|----------|
|
||
| message_bubble | Рендеринг пузыря сообщения с реакциями |
|
||
| message_list | Элемент списка сообщений (search/pinned) |
|
||
| chat_list_item | Элемент списка чатов |
|
||
| input_field | Поле ввода с курсором |
|
||
| emoji_picker | Сетка выбора реакций |
|
||
| modal | Центрированная модалка |
|
||
|
||
### config/ — Конфигурация
|
||
|
||
- **mod.rs** — struct Config, GeneralConfig, ColorsConfig, NotificationsConfig
|
||
- **keybindings.rs** — Command enum (30+ команд), кастомные горячие клавиши
|
||
- **validation.rs** — валидация timezone, цветов
|
||
- **loader.rs** — загрузка из `~/.config/tele-tui/config.toml`, credentials
|
||
|
||
## Тестирование
|
||
|
||
**500+ тестов** через `cargo test` (без TDLib).
|
||
|
||
**Инфраструктура**:
|
||
- `TestAppBuilder` — fluent API для создания App с нужным состоянием
|
||
- `FakeTdClient` — мок TDLib, реализует TdClientTrait
|
||
- `TestMessageBuilder` — создание тестовых сообщений
|
||
|
||
**Типы тестов**:
|
||
- Unit-тесты — в `#[cfg(test)]` секциях модулей
|
||
- Integration-тесты — в `tests/` (навигация, отправка, UI рендеринг)
|
||
- Doc-тесты — примеры в документации
|
||
- E2E — smoke и user journey тесты
|
||
|
||
## Потоки выполнения
|
||
|
||
```
|
||
Main thread TDLib thread
|
||
│ │
|
||
│ ◄── mpsc ─────── │ td_client.receive() в Tokio task
|
||
│ │
|
||
├── poll events │
|
||
├── handle input │
|
||
├── update state │
|
||
├── render UI │
|
||
└── sleep 16ms ──► │
|
||
```
|
||
|
||
## Рантайм файлы
|
||
|
||
| Путь | Описание |
|
||
|------|----------|
|
||
| `~/.config/tele-tui/config.toml` | Пользовательская конфигурация |
|
||
| `~/.config/tele-tui/credentials` | API_ID и API_HASH |
|
||
| `tdlib_data/` | TDLib сессия (НЕ коммитится) |
|
||
|
||
## Зависимости
|
||
|
||
| Категория | Крейт | Назначение |
|
||
|-----------|-------|------------|
|
||
| UI | ratatui 0.29 | TUI framework |
|
||
| UI | crossterm 0.28 | Terminal control |
|
||
| Telegram | tdlib-rs 1.1 | TDLib bindings |
|
||
| Async | tokio 1.x | Async runtime |
|
||
| Config | serde + toml | Serialization |
|
||
| Time | chrono 0.4 | Date/time |
|
||
| System | dirs 5.0 | XDG directories |
|
||
| System | arboard 3.4 | Clipboard |
|
||
| Notify | notify-rust 4.11 | Desktop уведомления (feature) |
|
||
| URL | open 5.0 | Открытие URL (feature) |
|