tm2027 · борд

Кто в дверях

Менеджер мобильных соединений: кто подключён сейчас, кто приходил раньше, кого выгнать и как сменить замок. Это не одна кнопка, а восемь независимых решений - от «телефон вообще не представляется» до «у каждого свой ключ, и его можно отнять». Каждая карточка рисует настоящий лист деки в её же чернилах, с этим одним решением внутри. Внизу пульт: он собирает лист целиком из того, что выбрано.

Что есть сегодня hello{token, proto} - и всё. Дека знает сколько телефонов подключено (CLIENTS: AtomicUsize), но не знает каких. Токен один на всех, лежит в mobile.json.
Личность стоит правки телефонов любой список «кто» начинается с того, что телефон себя называет. Это правка Protocol.kt, Wire.swift и ClientMessage::Hello - и новый APK с новой сборкой iOS.
Отзыв честен только при своём ключе пока токен общий, «забыть устройство» - это просьба, а не запрет: тот же токен входит снова. Настоящий отзыв - только вариант 1C.
Пиннинг не трогаем зря отпечаток сертификата пришит в каждом телефоне. Перевыпуск ключа деки ломает пиннинг у всех сразу - это отдельная красная кнопка, не побочный эффект.
1 · кто такой клиент

С этого всё начинается: чтобы показать список, нужно знать, из чего он состоит. Сейчас у деки нет ничего, кроме сокета.

1A

Адрес и всё

Протокол не трогаем. Клиент - это его сокет: адрес, порт, сколько уже висит. Телефоны не надо пересобирать, менеджер появляется сегодня. Плата: два телефона в одной сети неразличимы, а после каждого переподключения это «кто-то новый» - истории быть не может в принципе.

цена: малая - реестр живых клиентов в mobile_gateway, peer_addr() при accept; телефоны не трогаются
1B

Телефон представляется

hello обрастает device{id, name, platform}: id рождается на телефоне при паринге и живёт в его хранилище, имя берётся из модели устройства и правится руками. Список становится узнаваемым, история склеивается по id. Id подделываем - но токен и так общий, так что хуже не стало.

цена: средняя - ClientMessage::Hello, Protocol.kt, Wire.swift, новый APK и сборка iOS
1C

Дека выдаёт удостоверение

QR несёт не общий токен, а код на паринг. Первый hello по нему дека отвечает выпуском: у устройства теперь собственный токен, записанный в mobile.json рядом с его именем. Общего секрета больше нет, и «забыть устройство» действительно закрывает дверь именно ему.

цена: большая - формат mobile.json, миграция старого общего токена, выпуск на стороне деки, хранение на обоих клиентах
2 · что помнится

«Кто подключался» - это вопрос к памяти, а память надо где-то держать.

2A

Только живое

Лист показывает тех, кто на проводе сию секунду, и ничего больше. Закрылся сокет - строка ушла. Ничего не пишется и не стареет; вопрос «кто заходил ночью» остаётся без ответа.

цена: никакая - реестр живёт в памяти шлюза
2B

Кольцо на полсотни

Под живыми - те, кто был: последние пятьдесят подключений кольцом в памяти процесса. «Кто заходил сегодня» есть, «кто заходил на той неделе» - нет, и перезапуск деки стирает всё. Зато на диск не ложится ни байта.

цена: малая - VecDeque на 50 записей
2C

Журнал на диске

У устройства появляется досье в mobile.json: когда увидели впервые, когда в последний раз, сколько раз приходило, с какого адреса. Переживает перезапуск и обновление деки. Требует личности - 1B или 1C; с 1A писать нечего, кроме адресов.

цена: средняя - devices[] в конфиге, запись при каждом hello и разрыве
3 · что видно про живого

Сколько подробностей на строке. Всё нужное шлюз уже держит - вопрос, что из этого выносить на лист.

3A

Одна строка

Имя, адрес, сколько уже подключён. Лист читается одним взглядом и не мигает. На вопрос «а что он там делает» ответа нет.

цена: никакая
3B

И что у него на глазах

Второй строкой - пан, который телефон смотрит прямо сейчас, и когда в него в последний раз печатали. Это ровно то, чего не видно с деки: экран у тебя перед носом, а кто-то читает через него другой пан. Данные уже лежат в Client.watch - выносить почти нечего.

цена: малая - watch.key и watch.pane_id наружу через реестр
3C

И чего это стоит

Плюс телеметрия: кадров в секунду, сколько килобайт ушло за сессию, задержка по ping/pong, сколько раз стрим рвался и начинался с полного кадра. Отвечает на «почему рация греется» и «почему у него всё тормозит». Плата: строка живёт и дёргается, лист перерисовывается постоянно.

цена: средняя - счётчики-атомики в Client, замер RTT на pong
4 · чем можно ударить

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

4A

Отключить

Рвём сокет выбранного клиента. Телефон, если он рядом и приложение открыто, вернётся через секунду сам - так что это не изгнание, а способ освободить слот из восьми и оборвать зависший стрим.

цена: малая - AtomicBool на клиента, петля и так просыпается каждые 10 мс
4B

И забыть

Устройство вычёркивается из деки: сокет рвётся, досье уходит, вход закрывается. Насколько закрывается - зависит от оси 1: при 1C его токен просто перестаёт существовать, при 1B это блок-лист по id, который обходится переустановкой приложения.

цена: малая поверх 1C, честнее не бывает; поверх 1B - полумера
4C

И закрыть дверь совсем

Тумблер на весь шлюз: слушатель закрывается, порт исчезает с тайлнета, живые клиенты отваливаются. Полезно, когда деку оставляют одну надолго. Сейчас шлюз стартует один раз и живёт до конца процесса - остановки у него нет вообще.

цена: средняя - Gateway::stop(), которого нет: accept-петля должна уметь просыпаться и умирать
5 · что устройству можно

Сейчас телефон, вошедший в дверь, может печатать в любой пан любого сервера - включая тот, что за SSH.

5A

Всё или ничего

Как сегодня: вошёл - значит свой. Нет ни настройки, ни объяснения, что она значит.

цена: никакая
5B

Смотреть или печатать

На устройство - тумблер. Смотрящее получает кадры как обычно, но type и key ему отвечают отказом. Это режим «показать кому-то, что творится на деке», и он же - разумный дефолт для только что впущенного устройства.

цена: малая - одна проверка в двух ветках handle
5C

И только свои серверы

Устройству видно не весь флот, а отмеченные herdr-серверы: телефон в кармане видит LOCAL, но не продакшн за SSH. Фильтр в ответе на panes и отказ в watch на чужой сервер.

цена: средняя - набор серверов в досье, фильтр в ask_panes и в begin_watch
6 · замок

«Перегенерировать ключ» - это на самом деле два разных ключа, и они ломают разное.

6A

Один замок на всех

Как сегодня: токен общий. Кнопка СМЕНИТЬ ЗАМОК мнёт новый токен, все телефоны отваливаются разом и паруются заново с новым QR. Грубо, зато понятно и работает без правки телефонов.

цена: малая - new_token(), сохранение, разрыв всех живых
6B

Ключ у каждого свой

Следствие 1C: у строки появляется свой перевыпустить - этот телефон паруется заново, остальные не замечают. Общая «сменить замок» остаётся отдельно, для случая «отдал деку в ремонт».

цена: малая поверх 1C; невозможно без него
6C

И ключ самой деки

Второй, тяжёлый ключ - сертификат. Перевыпуск меняет отпечаток, а он пришит в каждом телефоне: пиннинг у всех протухает, паринг заново у всех без исключения. Нужен ровно один раз - если ключ деки утёк. Поэтому кнопка отдельная, красная и со спросом.

цена: средняя - новый Identity, перезапуск слушателя, диалог подтверждения
7 · как впускается новый

Сегодня QR - вечный пропуск: кто его когда-то сфотографировал, войдёт и через месяц.

7A

QR открыт всегда

Как сегодня. Один раз спарился - и всё; удобно, пока телефон один и он твой.

цена: никакая
7B

Код тухнет

Код на паринг живёт пять минут и одно устройство; на листе тикает таймер. Скрин QR, уехавший в чужую переписку, через пять минут - картинка. Плата: паринг стал делом, которое надо успеть.

цена: малая поверх 1C - у кода уже есть срок и счётчик
7C

Дека спрашивает

Новый телефон стучится - и ждёт, пока на деке не ответят: Pixel 8 с 100.83.117.58 просится - впустить? Ровно тот диалог, что уже есть для host key SSH. Знакомые устройства входят молча, чужой не войдёт, даже зная код.

цена: средняя - клиент ждёт в pending, вопрос гоняется в UI-поток тем же каналом, что MobileQuery
8 · где эта кнопка живёт

Просили «ещё кнопку» - вопрос, куда её ставить.

8A

Вторая вкладка паринга

Лист MOBILE PAIR получает два таба: ПАРА с QR и УСТРОЙСТВА со списком. Одно место про телефоны, одна горячая клавиша, ноль новых кнопок в подвале. Табов в листах деки пока нет ни одного - это новый приём.

цена: малая - MobilePairSheet обрастает вкладкой
8B

Свой лист

Отдельный лист MOBILE DEVICES: кнопка в подвале рядом с F1 и строка в палитре. Список - главное, паринг - кнопка внутри него (ДОБАВИТЬ ТЕЛЕФОН открывает QR). Ровно та же механика, что у листов деки сегодня.

цена: малая - ещё один лист по образцу существующих
8C

Строкой в рельсе

Никакого листа: в рельсе появляется заголовок PHONES, а телефоны стоят под ним строками, как паны под сервером - с теми же плашками состояния и тем же меню строки для действий. Телефон становится частью флота. Плата: рельс мы только что чистили, а это ему обратно две-три строки.

цена: средняя - новый род строки рельса и его меню; но спорит с «Тише рельс»
пульт

Пульт собирает лист из выбранного: личность даёт вид строки, память - нижний ярус, подробности - что на строке, действия и права - глаголы справа, замок и паринг - подвал. Выбирай в секциях выше или прямо тут - это одно и то же решение, показанное дважды.

выбрано 0 из 8
кликни по карточке - или по тумблеру на пульте