y83 code / инструмент

Туннели

Экран туннелей — состояние SSH-туннелей ко всем сохранённым серверам сразу, в отличие от экрана «Удалённые агенты», где каждый сервер проверяется отдельно.

раздел реестра
Безопасность и сеть
код
853 строк в 2 файлах
документ
25-tunnels.md
Раздел: Security & Network
Идентификатор: tunnels · Экран: ui/tunnels/TunnelsScreen.kt (429) + TunnelsViewModel.kt (361)
Снимок: 2026-10-11

1. Зачем и что это

Ключевая особенность: список обновляется раз в 5 секунд, пока экран активен, — туннели живут и меняются на стороне backend, и экран показывает это без ручного обновления.

Управление: открыть, переподключить, закрыть, проверить «Check now», перезапустить remote-демон и открыть его логи.

2. Как попасть

Хаб инструментов → секция Security & Network → карточка «Туннели» (hub_tunnels_title, подпись «Обратные SSH-туннели, состояние и переподключения», тайл — «Туннель»).

Откуда ещёПуть
Мостapp_navigate с screen: "tunnels"

Маршрут: Screen.kt → MainRouter (TunnelsScreen).

Шапка — терминальная y83@tunnels :~$, в meta видно «N active · M servers».

3. Экран: элементы и действия

ЭлементЧто делаетГде в коде
ШапкаПромпт, мета, состояниеTUNNELS_PROMPT, tunnelsMetaLabel
Карточка туннеляTunnelCardТочка статуса, имя, хост, порт, метки
Кнопка OpenОткрыть туннельopen(serverId)
Кнопка Reconnectclose + openreconnect(serverId)
Кнопка CloseЗакрыть туннельclose(serverId)
Кнопка Check nowПроверка и лечение обоих направленийcheck(serverId)
Кнопка Restart daemonПерезапуск codex app-server на сервереrestartDaemon(serverId)
Кнопка LogsЛоги демона в диалогеloadDaemonLogs, DaemonLogsDialog
Копирование портаcopyPort — локальный порт в буферcopyPort

4. Возможности подробно

Список и обновление

refresh(silent) берёт все серверы из App.remoteServerDao().getAll() и все туннели одним запросом tunnelStatusAll(), затем mergeTunnelRows склеивает их по serverId. Серверы без туннеля не прячутся — они показываются со статусом disconnected.

Пока экран активен, список обновляется раз в 5 секунд (delay(5_000)). Фоновый поллинг идёт в «silent»-режиме: не мигает лоадером и не сыпет ошибками, а ошибка предыдущего видна остаётся.

Статусы и цвета

tunnelStatusColor и tunnelStatusLabel (tunnel_up → «tunnel up»):

СтатусЦветСмысл
ready, tunnel_up, codex_startingуспехтуннель живой
connecting, reconnectingпредупреждениеподнимается
failedошибкаупал
прочеенейтральныйнеизвестно / не поднят

Разбор результата проверки

tunnelStatusAll возвращает по каждому туннелю: status, localPort, reverseHealthy, daemonRunning, lastError, lastErrorKind, lastErrorAt, errorActive, lastCheckAt, reconnectCount.

Важное различие, зафиксированное в скилле y83-remote:

  • ready + непустой lastError — норма (сбой пережит), а не ошибка;
  • смотреть надо на errorActive (сбой всё ещё актуален) и на reverseHealthy/daemonRunning;
  • host нужен, когда записи сервера в приложении уже нет.

Здоровье туннеля считается как ready && reverseHealthy && daemonRunning.

Действия

ДействиеЧто делает
openPOST /tunnel/open с креды сервера; успех = статус ready и валидный localPort
reconnectclose + open; креды не нужны — backend берёт их из самого туннеля
closePOST /tunnel/close
checkPOST /tunnel/check — проверяет оба направления и лечит их
restartDaemonPOST /remote/service с действием restart (codex app-server)
loadDaemonLogsЛоги демона в диалог

Метка «disconnected» ставится до запроса на закрытие (markDisconnected), чтобы watchdog не успел пересоздать туннель за пользователя; при неудаче метка снимается (clearDisconnected).

5. Данные: БД, файлы, настройки

ЧтоГде лежитКак меняетсяКто читает
Список серверовRoom (RemoteServerEntity)Экран серверовСклейка строк
Статус туннелейBackend (in-memory + проверки)tunnelStatusAllЭкран
Метка «пользователь закрыл»RemoteTunnelIntentmarkDisconnected / clearDisconnectedWatchdog

6. Backend: REST/роуты

Метод и путьНазначение
GET /api/v1/remote/tunnel/statusстатусы всех туннелей
POST /api/v1/remote/tunnel/openоткрыть туннель к серверу
POST /api/v1/remote/tunnel/closeзакрыть туннель
POST /api/v1/remote/tunnel/reconnectпереподнять туннель
POST /api/v1/remote/tunnel/check«Check now»: проверить и вылечить
POST /api/v1/remote/serviceдействие над codex app-server (restart)

Роуты: backend/internal/api/v1/routes.go:416–423.

7. Мост и MCP

ЧтоКакПримечание
Открыть экранapp_navigate с screen: "tunnels"BridgeScreenCatalog
ДиагностикаGET …/tunnel/status, POST …/tunnel/checkСкилл y83-remote
e2e-проверкаPROBE=1 PROBE_MCP=1 bash scripts/remote-e2e.sh <host>Скилл y83-remote

8. Настройки, конфиг, квоты и лимиты

ПараметрЗначениеГде задаётся
Интервал опроса5 секундЭкран (delay(5_000))
Здоровье туннеляready + reverseHealthy + daemonRunningФормула в скилле y83-remote
Серверов в спискевсе из RoommergeTunnelRows

9. Ловушки и ограничения

  • lastError — это история, а не текущая проблема. Пережитый сбой не должен пугать; смотрите на errorActive и reverseHealthy/daemonRunning.
  • Поллинг каждые 5 секунд держит постоянный запрос к backend, пока экран открыт. При слабой сети это заметно.
  • Reconnect не требует кред. Backend берёт их из самого туннеля; если туннеля ещё нет, сначала нужен open.
  • Метка «disconnected» ставится до запроса — при сбое сети карточка может показать disconnected, хотя туннель ещё жив.
  • localPort = 0 означает, что туннель не поднят. Порт можно скопировать в буфер, чтобы подключиться вручную.
  • Логи демона открываются диалогом и требуют доступа по SSH к серверу.
  • Серверы без туннеля не скрываются — они видны со статусом disconnected, что может выглядеть как «сломанный» туннель.

10. Источники правды

  • app/src/main/java/com/y83/ws/ui/tunnels/TunnelsScreen.kt — экран, карточки, диалог логов.
  • app/src/main/java/com/y83/ws/ui/tunnels/TunnelsViewModel.kt — состояние, склейка, действия.
  • app/src/main/java/com/y83/ws/data/api/TunnelListApi.kt — DTO и клиент.
  • app/src/main/java/com/y83/ws/data/RemoteTunnelIntent.kt — метки «пользователь закрыл туннель».
  • backend/internal/api/v1/routes.go:416–423 — роуты туннелей.
  • skills/y83-remote/SKILL.md — архитектура и диагностика туннелей.

Источник: docs/project/hub/25-tunnels.md · Безопасность и сеть · 853 строк в 2 файлах. Страница собирается из документации проекта при сборке сайта.