Будни вайбкодера

Кукарек

Почему без VPN не работало

Шифрование, сделанное ради приватности, попутно вылечило блокировку. А починка мелодии убила звук в звонке.

Вчера Кукарек научился звонить. Сегодня он вышел по ссылке, перестал требовать VPN и обзавёлся галочками «доставлено» и «прочитано». Между этими событиями я успел сломать звук в звонке собственной вчерашней починкой — об этом тоже расскажу, потому что история поучительная.

Сначала хорошее: ссылка

Apple пропустила приложение в TestFlight за сутки. Теперь его ставит кто угодно по обычной ссылке — без приглашений на почту и заведения людей в аккаунт разработчика.

Отдельно приятная деталь: ожидание оказалось разовым. Следующая сборка ушла тем же людям без нового ревью — Apple смотрит на приложение, а не на каждую правку. То есть сутки платишь один раз за вход, а дальше правки доезжают за минуты.

Почему без VPN не работало

А вот это оказалось интересным.

До сегодняшнего дня приложение ходило на сервер так:

ws://<адрес сервера>:8090

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

Сегодня у проекта появился домен, а вместе с ним сертификат:

wss://kukarek.ggwplab.com/ws

Обычный HTTPS на 443 порту. Снаружи это неотличимо от захода на любой сайт: видно только имя домена, всё остальное зашифровано.

И оно заработало: в тот же день пошли успешные подключения с российских домашних и мобильных провайдеров, без всякого VPN.

Забавно, что шифрование я делал ради приватности — переписка и договорённость о звонке шли открытым текстом, и это надо было закрывать в любом случае. Про VPN я узнал уже потом. Лекарство подействовало от болезни, которую не лечили.

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

Как починка мелодии убила звук

Теперь про то, чем я сегодня занимался дольше всего.

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

try session.setActive(true)

Мелодия заиграла. А звук в разговоре пропал полностью — с обеих сторон.

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

Отдельно отмечу, каким окольным путём я к этому пришёл. Сначала я подумал на сеть — благо повод был, звонки как раз перестали требовать VPN. Полез в записи ретранслятора и увидел, что телефоны пытаются достучаться друг до друга только по домашним адресам вида 192.168.x.x, а публичных в обмене нет вовсе. Красивая версия: кандидаты теряются по дороге, сервер их отбрасывает.

Версия оказалась неверной. Я добавил на сервер подсчёт потерь, попросил сделать один звонок — и увидел, что доходит всё:

signal.candidate тип=host
signal.candidate тип=srflx
signal.candidate тип=relay

Ни одной потери. Сеть была ни при чём, виноват был я. Полчаса на диагностику вместо получаса на «починку не того» — обмен, о котором не жалею.

Галочки

Появились статусы сообщений: часы — в пути, галочка — сервер принял и держит, две галочки — доставлено на телефон, две в белой заливке — прочитано.

Заодно закрылась дыра, которой раньше не было видно. Если собеседник не в сети, сообщение уходило в очередь — и отправитель больше не узнавал о нём ничего никогда. Оно молча доставлялось спустя часы. Теперь, когда человек появляется в сети, автору приходит отметка о доставке на всё, что пролежало в очереди.

И одно решение, которое стоит объяснить. Отметки о прочтении можно выключить, и это не для галочки в списке функций. Отметка сообщает не только «я прочитал» — она сообщает «я сейчас в сети и открыл нашу переписку». Для мессенджера, который называет себя анонимным, такое обязано быть выключаемым. По умолчанию включены, как принято, но переключатель на видном месте.

Мелкое, но важное

Различать «доставлено» и «прочитано» я сначала сделал прозрачностью: 75% белого против 100%. На значке в девять пунктов такую разницу не видно вовсе — состояния сливались в одно, и вся затея теряла смысл. Переделал на форму: прочитанное отличается белой заливкой, а форму видно на любом фоне.

Это второй раз за проект, когда полагаться на оттенок оказалось ошибкой. В первый раз белый текст сообщений оказался на белом фоне в тёмной теме. Правило, которое я для себя вывел: если разницу между двумя состояниями нельзя объяснить словами «другая форма», её, скорее всего, не увидят.