История разработки: Mercury Messenger
2 поста
Две хорошие новости для любителей интернета, технологий, мессенджеров и дневников разработки.
Как вы, конечно, помните, я разрабатываю мессенджер неподвластный цензуре и свободный от подписок и рекламы. Ну или посмотрите предыдущий пост Как написать собственный мессенджер и сохранить рассудок, кто не помнит.
Первая версия мессенджера, про которую был предыдущий пост, работала на технологии WebRTC: это хорошо проработанный набор протоколов для установления прямого соединения между устройствами через интернет и передачи текстовой/бинарной и медиа информации, такой как голос и видео. WebRTC настолько популярен, что, в общем-то, все видеоконференции сейчас работают на этом фреймворке - его поддержка вшита во все браузеры а для мобильных разработчиков поставляются и регулярно обновляются готовые библиотеки. Если очень кратко, два клиента, которые хотят установить прямое соединение, получают информацию о своем присутствии в интернете от STUN-сервера (сокр. от англ. Session Traversal Utilities for NAT, это сетевой протокол, который позволяет клиенту определить свой внешний IP-адрес, способ трансляции адреса и порта во внешней сети) и публикует все что нашел на особом сигнальном сервере. Сигнальный сервер для обоих клиентов должен быть один и тот же, а STUN-сервера - какие угодно, их много публичных и бесплатных.
Проблемы начинаются, когда один или оба клиента спрятаны за NAT (Network Adress Translation, это технология, которые используют роутеры чтобы преобразовать адреса внутренней сети в адреса интернета и обратно) и входящие соединения невозможны, то есть в современном интернете - практически всегда. Для того, чтобы устройства все-таки смогли как-то установить соединение, WebRTC предполагает использование TURN-серверов (Traversal Using Relays around NAT), специальных реле, которые передают зашифрованные аудио/видео/данные потоки между устройствами когда прямое соединение не может быть установлено. Для своего приложения я использовал TURN-сервера от metered.ca.
Когда я опубликовал первую версию мессенджера, внезапно обнаружилось, что metered.ca в России заблокирован, давно и прочно. Общение не задалось.
Так вот, первая хорошая новость - я, наконец-то, полностью, окончательно и бесповоротно (потому что я никогда не возьмусь переделывать это взад) перевел мессенджер на libp2p. Это открытый фреймворк для разработки P2P приложений, со встроенным шифрованием, обходом NAT и поиском клиентов в распределенных хэш-таблицах. libp2p подразумевает, что где-то в интернете должны быть доступны стартовые ноды с известными адресами, а дальше по мере роста количества клиентов, распределенная сеть будет становиться все устойчивее и устойчивее. Пока я выкатил 4 стартовые ноды, и, если их заблокируют, я легко смогу перевыпустить их с новыми адресами и обновить приложение.




Япония, к слову, не блокирует ничего пока, там и первая версия работала. Но обновленная - намного лучше.
libp2p работает немного похоже на WebRTC но есть и принципиальные отличия. Например, когда клиент ААА хочет установить соединение с клиентом АББ, в случае WebRTC этим занимался сигнальный сервер - он знал контактные данные обоих клиентов и дружил их друг с другом:
В случае libp2p, никакого сервера больше нет, некому сообщить ААА контактные данные АББ и наоборот. Но вместо этой потенциальной точки отказа, у нас есть распределенная хэш-таблица с контактными данными, где ААА может запросить контакты АББ и инициировать соединение. Дальше либо будет установлено прямое соединение если это возможно, если нет, то потоки данных будут транслироваться через одну из нод, до которой оба ААА и АББ соединения уже установили. Практически можно сказать, что вместо одного большого сигнального сервера у нас теперь много маленьких сигнальненьких серверочков.
Аудио и видео звонки я оставил работать через WebRTC, для этого в свои ноды я добавил встроенный TURN-сервер на основе открытого coturn. Так как контакты обоих устройств уже известны - вы не можете позвонить не установив соединение - сигнальный сервер не нужен. 4 слабеньких ноды - это, конечно, не панацея, но пару сотен одновременных звонков выдержат. В теории, если надо, и для усиленной безопасности, люди смогут публиковать в интернете свои собственные ноды - и привязать их к приложению, это все уже реализовано.
И это вторая хорошая новость - я собираюсь открыть исходники под какой-нибудь подходящей лицензией, и уже начал подготовку - автосборки, автоформат кода, автовыполнение тестов при открытии пулл-реквестов, и все такое. Процесс небыстрый, к сожалению.
Из других нововведений: добавил групповые чаты, один аккаунт теперь может быть зарегистрирован на нескольких устройствах, все они будут синхронизированы, улучшена передача файлов.
В следующем посте, пожалуй, расскажу об интересном механизме синхронизации сообщений. Так как мой мессенджер не имеет серверной части, вся переписка хранится на устройстве. Для переезда с одного телефона на другой, можно сделать зашифрованный бэкап, но если единственный телефон умер - переписку не восстановить. Но есть вариант загрузить всю историю сообщений от ваших собеседников! И она загрузится. Если, конечно, вы не потеряли сам аккаунт, так что не забывайте сохранять фразу безопасности в надежном месте.
Если захотите пощупать это приложение самостоятельно, ссылку на Google Play я оставлю в комментариях.
Где-то с полгода назад, когда началась эта история с блокировками и замедлением, я задался вопросом: "Ведь скоро заблокировано будет чуть более, чем всё. А как мне, собственно, при этом всём общаться с семьей и друзьями, когда я живу заграницей, а они в России?". Я вышел в интернет с таким вопросом, и начал поиски удобного надежного мессенджера, чтоб чисто писать, звонить и скидывать мемы. Несколько вариантов нашлись довольно быстро, какие-то заработали у родителей, какие-то нет, парочка отвалилась в процессе тестирования, в общем, это не особо важно, уже даже на Пикабу встречал несколько обсуждений, так что обойдемся без подробностей.
Во время всего этого священнодействия, меня не отпускала одна мысль. А чего бы не сделать свой мессенджер? Опыт есть, в прошлом я плотно занимался разработкой под Андроид по работе, да и своих личных приложений опубликовал с десяток. Тем более, у меня уже есть свое родное приложение для видеоконференций, peer-to-peer: прямое соединение от устройства до устройства, никаких лишних серверов, одна красота. Ну разве что надо будет заменить конференции на звонки, прикрутить к нему список контактов, чаты, профили, криптографию, аутентификацию, цифровые подписи, подтверждения и удаления контактов, базу данных, индексы, миграции, транзакции, пейджинг, навигацию, передачу сообщений, файлов, уведомления, настройки, поиск, блэклист, потом интегрировать все это великолепие со службами телеком Андроида, добавить просмотр картинок и видео, тесты, ботов, шэринг, перевести на основные мировые языки. Что может быть проще?
За 5 месяцев работы по вечерам и выходным (ну, конечно, не каждый день), 543 коммита и примерно 40000 строк кода, получилось что-то более-менее удобоваримое и стабильное.
Так как человек я бедный экономный, и не планирую поддерживать дорогую серверную инфраструктуру, даже чаты в моем приложении работают через p2p - прямое соединение между телефонами. Это, кстати, редкость среди публично доступных мессенджеров, подавляющее большинство используют сервис пуш-уведомлений Гугла или Эппл для доставки сообщений. В моем случае, сначала оба устройства устанавливают прямое соединение друг с другом, и только в случае успеха начинают обмениваться шифрованными мемами со страшной силой без промежуточного сервера. Если соединиться прямо сейчас не удалось, все будет локально сохранено и доставлено автоматом при первой же возможности. Кое-какой обмен с сервером для установления прямого соединения все равно необходим - телефоны должны обменяться информацией о своем подключении и IP-адресах, но как только соединение установлено - сервер можно даже выключить - общению это не помешает.
И в этом заключается как огромное преимущество, так и некоторые недостатки: переписки и звонки мало того что закодированы сквозным шифрованием, так еще и никогда даже не попадают на сервер - это чертовки приватно и секьюрно и не надо сильно беспокоиться об утечках - невозможно слить то, чего нет. С другой стороны, теперь конечные устройства ответственны за доставку текстовых сообщение и пакетов данных - сам телефон должен организовать повторную доставку, если что пошло не так, для всех переписок. Это не проблема вовсе для частных контактов, небольшая трудность для групповых чатов на 50-100 человек, но огромная головная боль для публичных каналов на миллионную аудиторию. Публичных каналов, поэтому, нет. Групповых чатов, впрочем, тоже пока нет.
Чтобы добавить кого-то в свой список контактов нужно просканировать QR-код с временным криптоключём, или добавить по идентификатору и ждать, пока тот вручную подтвердит добавление и клиенты обменяются цифровыми подписями.
Эта девстори не была бы полной, если бы я не упомянул о самом трудоемком (да и самом интересном). Я ж ниибаца профессионал, на работе я делаю софт, которым пользуются миллионы, весь такой safety-critical С++ покрытый на 100% тестами и анализаторами по самую макушку. Нельзя же просто взять и сделать Ардроид приложение, это слишком просто, надо извернуться и с самого начала создать целый фреймворк для мессенджеров.
Я разработал С++ ядро, единое для всех поатформ, а приложение Андроид должно по задумке быть только тонким клитентом вокруг этого ядра. Забегая вперед, скажу что задумка удалась почти полностью. Конечное приложение действительно работает как оболочка вокруг единого производительного и набитого тестами ядра, и если я захочу сделать приложение, например, для Эппл, мне нужно будет только скопировать пользовательский интерфейс, биндинги на ядро и интеграцию с родными службами айфона. Вся логика, настройки, все модели, хранилище, шифрование и вообще всё-всё - уже в ядре. Это здорово, но насколько же все усложнилось, кто бы знал. Тем не менее, оно работает, и в общем, работает весьма неплохо, потребление приложением батареи за день на фоне всего остального вообще не заметно. Есть еще поле для оптимизации хранения в базе данных, да и ядро можно порефакторить во имя вечного и недостижимого приближения к идеалу, но в целом и так хорошо.
Итого, получилось довольно неплохое приложение для общения. Уже больше недели я с семьей и друзьями используем его для ежедневных переписок и пока все всех устраивает и, более того, нравится. Настолько, что я решил выложить мессенджер в Google Play, а мою девстори прямо сюда. Для желающих скачать и потрогать, ссылка вот https://play.google.com/store/apps/details?id=hela.eillance, там нет рекламы, нет подписок и платного контента. И вряд ли когда-либо будет, добавлять рекламу или подписку в мессенджер, когда вокруг столько бесплатных альтернатив (как, например, поддерживаемый на государственном уровне, MAX/sarcasm), это просто приговор.
Кстати, не переименовать ли мне его в Sarcasm Chat?