Fix readme

This commit is contained in:
Magnus Root 2026-07-17 09:35:38 +03:00
parent ff9a0aae8d
commit 4c4b6412cd

127
README.md
View file

@ -311,133 +311,6 @@ strikeout/inverse, курсор (инверсией текущей ячейки)
одинаковым стилем схлопываются в один `Span`, чтобы не плодить по Span на
символ на длинных однотонных строках.
## Что реально работает
Ниже — история того, что уже прогонялось через настоящий `cargo build` на
реальной машине (не только в песочнице), а не только через сверку с
документацией. Первый прогон нашёл 7 реальных ошибок компиляции, второй —
ещё одну (сигнатура `Channel::data`). После этого **`cargo build --release`
прошёл полностью** — остались только предупреждения о неиспользуемом коде
(почищены). Живое подключение к серверу/устройству пока не проверялось.
**Что было сломано и как исправлено (см. git-историю/этот README для
контекста, если он у тебя есть):**
- `async-trait` не был объявлен в `Cargo.toml`, хотя использовался everywhere
для `Transport` — добавлено.
- `russh::keys::learn_known_hosts` не реэкспортируется на верхнем уровне в
версии 0.62.2 (там есть только `check_known_hosts`) — записываем строку в
`~/.ssh/known_hosts` сами, через `PublicKey::to_openssh()` + дозапись в
файл, без обращения к приватным/непереэкспортированным функциям russh.
- `authenticate_publickey`/`authenticate_password` возвращают `AuthResult`
(с методом `.success() -> bool`), а не голый `bool`, как предполагалось
изначально — поправлено.
- `Handle::window_change` в этой версии не существует — только
`Channel::window_change`. Раз уж пришлось трогать эту часть, канал
(shell/PTY) целиком переехал в отдельную задачу, которая мультиплексирует
входящие сообщения от сервера и команды (write/resize/close) от
`Transport` через `tokio::select!`, вместо того чтобы держать `ChannelId`
и слать всё через `Handle`.
- `alacritty_terminal::event::WindowSize` не реализует нужный трейт
`Dimensions` для `Term::new`/`Term::resize` (это разные вещи: `WindowSize`
— размер в пикселях для PTY, `Dimensions` — размер в колонках/строках
символьной сетки) — завели свою маленькую структуру `GridSize` в `term.rs`.
- `Handle::data(...)` возвращает `Result<(), Bytes>` (не пропущенные данные
возвращаются как есть, а не завёрнуты в нормальный `Error`) — обёрнуто
через `map_err`, чтобы `?` не спотыкался о недостающий `impl StdError`.
- (Второй раунд, после того как первый прогон дошёл до `Channel::data`)
`Channel::data<R: AsyncRead + Unpin>(&self, data: R)` принимает
источник для чтения, а не готовый буфер/что-то конвертируемое через
`Into` (в отличие от `Handle::data`, у которого сигнатура другая) — вместо
`data.into()` теперь `channel.data(&data[..])`, `&[u8]` сам реализует
`AsyncRead`.
- (Третий раунд — уже не ошибка компиляции, а баг в поведении: экран при
запуске не очищался.) `enable_raw_mode()` включает построчный ввод, но
сам по себе не переключает терминал на отдельный "alternate screen
buffer" — тот самый механизм, из-за которого `vim`/`htop`/`less` рисуют
на чистом экране, а при выходе возвращают терминал ровно в то состояние,
в котором он был (включая историю команд шелла). Без него komiterm рисовал
свой UI поверх текущего скроллбэка — добавлены `enter_tui()`/`leave_tui()`
в `app.rs`, вызывающие `EnterAlternateScreen`/`LeaveAlternateScreen` из
`crossterm` парно с `enable_raw_mode()`/`disable_raw_mode()` на каждом
пути выхода из `run()` (их несколько — отмена выбора сессии, ошибка
подключения, обычное завершение).
- (Четвёртый раунд — **первое подключение к реальному SSH-серверу прошло
успешно**, но нашлось два визуальных бага.) Промпт passphrase от
`rpassword` (и TOFU-промпт known_hosts) пишет прямо в tty в обход
`ratatui``Terminal` про эту запись не знает и её не перерисовывает,
поэтому огрызок текста промпта оставался на экране поверх строки
состояния. Добавлен `terminal.clear()?` сразу после каждого
`transport::connect()`, случающегося уже внутри TUI (стартовый picker,
`F2`, `Enter` по сессии в фокусированной панели) — форсирует полную
перерисовку экрана с нуля вместо диффинга, который не видел "чужой" записи.
- (Пятый раунд, тот же скриншот.) Название сессии в боковой панели не
помещалось / было не видно целиком. Вероятная причина — "тяжёлые"
юникод-символы (● ➤ 📁 и т.п.), чья реальная ширина в конкретном шрифте
терминала может не совпадать с тем, что предполагает расчёт колонок в
`ratatui` (типичная проблема для символов вне базовой латиницы/кириллицы —
не все шрифты меряют их как честную одну ячейку). Заменил все декоративные
символы на простой ASCII (`*`, `>`, `[D]`, `_`, `-`) и увеличил
`SIDEBAR_WIDTH` с 24 до 30 колонок с запасом. Если после этого текст
всё ещё обрезается — это, вероятно, уже про шрифт терминала (кириллица
не всегда идеально моноширинная в некоторых шрифтах), а не про код.
- (Шестой раунд — не баг, а конфликт хоткея, плюс найденный заодно баг.)
Дефолт `quit` сменён с `ctrl+alt+c` на `f10` (конфликтовал с DE/WM у
пользователя; существующие `hotkeys.toml` это не трогает — старые
конфиги правятся вручную). Заодно нашлась дыра: если сессия завершалась
сама (`exit`/`Ctrl+D` в шелле), таб не закрывался, а следующая же клавиша
в нём валила **всё приложение**`tab.transport.write(...).await?`
пробрасывал ошибку записи в мёртвый канал через весь `main_loop`. Теперь
канал каждого таба каждый кадр проверяется на `TryRecvError::Disconnected`
(не просто "пусто сейчас", а "закрыт навсегда") — таб с завершившейся
сессией закрывается автоматически, без валящего приложение падения.
**Что осталось (честные пробелы):**
1. **ssh.rs**: `AuthMethod::Agent` **временно отключён** — метод, которым
это было изначально реализовано (`authenticate_future` на `Handle`, взят
из старого примера в репозитории russh), в используемой версии (0.62.2)
не существует. Актуальную замену не удалось подтвердить без живой
компиляции — вместо третьей попытки угадать API вслепую, честно
возвращаю ошибку с указанием использовать `Key` или `Password`. Если
agent важен — дай знать, разберёмся предметно по фактической ошибке
компилятора, как в этот раз.
2. **ui.rs**: мастер создания сессии (`n` в списке сессий) — текстовые поля
только добавляют/стирают символы с конца строки, без перемещения курсора
внутри неё и без валидации на лету (например, нечисловой порт просто
тихо упадёт на дефолт при парсинге). Для тех же целей `komiterm profile
add` (создание credential-профиля) по-прежнему только через
`komiterm profile add` в терминале, не из этого мастера — они пока не
связаны. Из боковой панели в режиме списка сессий (`F1`, не `F2`) `n`
пока не работает — только из самого пикера при `F2`/начальном запуске.
3. **sftp.rs**: закачка привязана к UI, но download/upload по-прежнему
грузят файл целиком в память, нет rename/mkdir/delete в браузере (у
SftpSession методы есть) — см. TODO в конце `sftp.rs`.
4. **hoststats.rs**: только Linux (`/proc`) и только SSH; опрос блокирует
главный цикл на время round-trip. Не проверено на реальном хосте.
5. **serial.rs**: создать serial-сессию можно и через мастер (`n`), и руками
в `sessions.toml` — но нет `SerialPort::available_ports()` ни там, ни
там (списка реально подключённых портов, а не текстового поля вслепую).
Не проверено на реальном устройстве.
6. **telnet.rs**: отвечаем на DO/WILL только для ECHO и SUPPRESS-GO-AHEAD;
NAWS (передача размера окна) не реализован.
7. **sshconfig.rs**: `Match`-блоки и полноценные glob-паттерны не поддержаны.
8. **profiles.rs**: добавление профиля — простые вопросы в stdin, не форма
в ratatui (осознанно: это CLI-подкоманда вне raw-режима основного TUI).
9. Версии крейтов в `Cargo.toml` по-прежнему не проверялись сборкой **в
песочнице** (тот же древний `rustc 1.75`, упирается в edition2024 на
первом же транзитивном пакете) — но теперь у нас есть подтверждение с
реальной машины на актуальном тулчейне, и именно оттуда взяты все
исправления выше.
## Дальше по roadmap (после MVP)
- SSH-туннели (local/remote/dynamic port forwarding) — russh это умеет
- Логирование сессии в файл
- NAWS для telnet (передача размера окна серверу)
- rename/mkdir/delete в SFTP-браузере (методы у SftpSession уже есть)
## Сборка
```bash