Skip to content

Архитектура

Компоненты

┌─────────────────────────────┐     ┌──────────────────────┐     ┌────────────────────┐
│          Ваш Mac            │     │        Релей         │     │  Telegram Mini App  │
│                             │     │                      │     │                    │
│  Демон Teleportus           │     │                      │     │                    │
│  ├── захват экрана          │ WS  │  ├── session router  │ WS  │  ├── WebSocket      │
│  ├── контроллер ввода       │────►│  ├── рассылка кадров │────►│  ├── JPEG-рендеринг │
│  ├── захват / вывод аудио   │◄────│  └── проверка входа  │◄────│  └── события ввода  │
│  ├── захват камеры          │     │                      │     │                    │
│  ├── расшифровка голоса     │     └──────────────────────┘     └────────────────────┘
│  └── AI-раннер              │
└─────────────────────────────┘

Демон

Демон — Node.js/Bun-процесс на вашем Mac.

Захват экрана — порождает предкомпилированный Swift-бинарник, который использует ScreenCaptureKit для захвата JPEG основного дисплея. Бинарник компилируется при первом запуске через системный swiftc. Захват приостанавливается пока нет подключённых зрителей.

Контроллер ввода — отправляет клики мышью, движения, нажатия клавиш и прокрутку. Текстовый ввод реализован через буфер обмена + Cmd+V — поддерживается любой Unicode без перемаппинга кодов.

Аудио — два нативных Swift-бинарника захватывают системный звук (выход) и воспроизводят аудио с микрофона (вход). Оба universal binary (arm64 + x86_64).

Камера — третий Swift-бинарник стримит дефолтную камеру через AVFoundation. Кадры с камеры никогда не пересылаются гостям шеринга.

Расшифровка голоса — аудио из Mini App расшифровывается локально через Whisper — небольшую голосовую модель, встроенную в демон и работающую прямо на вашем Mac. Аудио никуда не уходит для обработки.

AI-раннер — принимает инструкции на естественном языке от бота и выполняет их как многошаговые действия через Claude. AI имеет доступ к захвату экрана, контроллеру ввода и шелл-раннеру.

Релей

Релей работает как HTTP/WebSocket-сервер и разворачивается на любом хостинге с поддержкой WebSocket.

WebSocket-роутер — управляет одной комнатой на SESSION_TOKEN. Демон и Mini App подключаются к одной комнате по токену. Релей не интерпретирует кадры — он буферизует последний кадр и рассылает всем.

Авторизация — Mini App-подключения передают подписанные данные входа Telegram. Релей проверяет подпись, подтверждая что зритель — реальный пользователь Telegram. Гости шеринга проверяются отдельно через share-токен.

Кеш кадра — последний кадр каждой комнаты кешируется в памяти, чтобы новые зрители мгновенно получали картинку без ожидания следующего тика.

Устаревание демона — если WebSocket демона молчит 45 секунд, слот считается устаревшим и следующая регистрация его вытесняет. Это корректно обрабатывает циклы сна/пробуждения Mac.

Mini App

Mini App отдаётся как Telegram Web App:

  • Открывает WebSocket на релей через параметры URL сессии
  • Рендерит входящие JPEG-кадры
  • Переводит touch-события в input-сообщения (click, scroll, key, type)
  • Обрабатывает переключение экран/камера сменой источника
  • Записывает аудио микрофона и отправляет в демон через релей

Поток данных

тик захвата (каждые 1/FPS секунд)
  демон  →  бинарный JPEG-кадр  →  релей  →  broadcast всем клиентам комнаты

тап пользователя в Mini App
  Mini App  →  JSON input msg  →  релей  →  демон  →  диспатч ввода

голосовое сообщение
  Mini App  →  audio blob  →  релей  →  демон  →  Whisper → текст
  → обрабатывается как текстовый ввод

AI-задача (текст боту)
  Telegram бот  →  релей  →  демон  →  AI-раннер
  → захват экрана + действия ввода как побочные эффекты

Модель безопасности

  • Каждое Mini App-подключение проверяется по подписанным данным входа Telegram — анонимного доступа нет
  • Гости шеринга получают отдельный токен; им пересылаются только кадры экрана
  • Кадры камеры никогда не отправляются гостям шеринга
  • Релей не хранит кадры на диске — только последний кадр в памяти, вытесняется когда комната пустеет
  • Session-токены генерируются рандомно для каждого пользователя; инвалидируются по /revoke