MAX Light — легкая версия клиента MAX для ПК Windows

от автора

Всем ку! Пожалуй, стоит начать с того, что меня вообще сподвигло на создание данной версии:

  1. Нежелание некоторых юзеров пользоваться официальной версией для ПК по ряду причин:

    а) Требовательность к железу (даже видеокарту нагружает). А некоторым по работе приходится юзать МАХ на «уставших рабочих лошадках». Заявления, типа «эта тварь жрёт ресурсов больше, чем 1С».

    б) Постоянные обновления с полной переустановкой, а на момент написания статьи полный пакет официального МАХ весил 308 мб.

    в) Некоторые неудобства использования веб‑версии, особенно в режиме «Инкогнито». Чуть подробнее будет дальше в статье.

    г) Слежение за пользователем. Вроде, ничего особо криминального нет во встроенных трекерах, но бесит, когда тебя не спрашивают. Знаете, если Вы выходите из подъезда и бабульки на лавочке интересуются как у вас дела и куда направляетесь — это одно. Ваше дело — отвечать\не отвечать\соврать. А когда Вам при этом ещё и в трусы заглядывают без спроса — это уже другое.

  2. Не нашел хорошую альтернативу. Нет, есть конечно nemax‑mod для ПК, который представляет из себя оболочку для веб‑версии, но так такое… и сырое.

Значит, будем делать своё!

Итак, для начала выберем инструмент разработки, для этого есть некоторое количество моих «юзерфрендли принципов»:

а) Запуск на всём, чём можно. Некоторые из технологий и фреймворков будем использовать «заранее устаревшими». Выбор по старинке остановил на c# +.net framework 4.7. Конечно, можно было использовать более новые.NET 8\9\10, что гораздо упростило бы разработку и решило некоторых сложности, с которыми пришлось столкнуться. Но если у юзера Win10 без предустановленного.NET или даже Win7 (да, и такие отписываются в Issue на гитхабе), это создаст некоторые неудобства при первичном запуске.

б) Малый вес. Как можно меньше. Нет перегруженного интерфейса и прочих свистогуделок и прочего мусора.

в) Максимально простая установка. Поддержка обновлений. Желательно, удобных обновлений.

Ну что ж, приступаем!

  1. Для начала набросал простую оболочку, в которой запускается WebView2 с привязкой к сайту веб‑версии MAX и увидел несколько проблем:

    а) Хорошо, у меня есть окно, но как получать уведомления, если оно свёрнуто?

    б) При авторизации создается папка с файлами и кэшем веб‑версии в appdata. Меня это не устроило по ряду причин — по моему опыту хранение данных локально может быть на руку злоумышленникам. В своё время я легко получал доступ к перепискам различных мессенджеров, благодаря локальному хранению. И вообще, считаю папку с данными WebView2 — мусором. А пользователь не должен об этом задумываться при удалении мессенджера с рабочего компа.

    в) В принципе, при работе в режиме ‑inprivate (сиречь «в режиме Инкогнито»), создается временная папка, которая удаляется при закрытии окна, но тогда придется проходить авторизацию каждый раз при запуске.

  2. Мне понравилась идея с in private, но тогда нужно хранить ключ авторизации. Пишем перехватчик токенов на javascript. Легко и просто перехватываем токен авторизации, но как его хранить? Ответ лежит на поверхности — прямо в реестре с шифрованием по DPAPI — это решит сразу несколько проблем:

  • Не нужно постоянно проходить авторизацию

  • Токен «под рукой» для быстрого удаления

  • Копирование токена на другой комп не позволит использовать его на другой машине, так как DPAPI имеет жесткую привязку к windows user id, device id

  • Токен зашифрован и его нельзя «просто прочитать»

    Вопрос: кто‑то другой сел за комп и открыл эту программу. Либо она запустилась сама при загрузке системы и «посторонний» видит всю переписку. Решение — добавляем функцию пин‑кода. Опциональное, пользователь может отказаться и добавить пин‑код потом или удалить его.

    Логика работы парсера — при инициализации окна парсер проверяет, есть ли ключ авторизации в зашифрованном виде по месту хранения? Если есть — останавливается. Если нет — ждём авторизации от пользователя по QR‑коду. Как только токен перехвачен и сохранен — парсер останавливает работу.

    Не забываем про UX — добавляем в настройки удаление данных авторизации в один клик.

    3. Создаем иллюзию окна как отдельного мессенджера. Имеется ввиду необходимость сохранения положения окна и его размеров при каждом запуске. В том числе при наличии нескольких дисплеев. Сохраняем данные по размерам окна и координатам в реестре. Не шифруем )

Уведомления

  • Проводим опрос среди юзеров. Что нравится и не нравится, когда они используют оригинальную веб‑версию МАХ? Приходим к выводу, что нам необходимо:

  • Корректно всплывающие уведомления типа стандартных, но лучше и функциональнее.

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

    Значит, делаем уведомления в правом нижнем углу с нуля. Включаем логику определения получения новых сообщений. При взгляде на чат видим, что у нас есть три вида состояния — синий бейдж с количеством сообщений — новое непрочитанное. Серый бейдж — новое непрочитанное в чате, для которого пользователь выключил уведомления. Нет бейджа — нет новых сообщений. Изучаем веб‑страницу, ищем div’ы и классы, отвечающие за бейджи, парсим эти состояния. Дебажим.

    Передаем из javascript в c# данные. Пишем CustomNotification.cs, который будет рисовать нам уведомления в нижнем углу Windows.

    Прописываем определение состояния окна программы (мы же не хотим получать всплывающие уведомления прямо во время переписки?) — окно либо в фокусе, либо нет. Если нет — показываем уведомления. Опять дебажим…

    Парсим данные из чата с синим бейджем — аватар, имя\ник пользователя и тело сообщения. Всё это добавляем в наш нотификатор и снова и снова дебажим. Не забываем про такие нюансы как — крестик на уведомлении для быстрого закрытия, положение уведомления по, скажем так, Z‑координате (мы должны видеть уведомление из нашей программы поверх всех других окон, в том числе в 3D приложениях, но это не должно приводить к их сворачиванию).

    Добавляем функцию «антифлуд» — это когда кто‑то начинает спамить короткими сообщениями, и Вам это не нравится — показываем новые сообщения не чаще чем задано определённым временным лимитом. Добавляем проверку на дубли сообщений — когда Вы получили новое сообщение, то получили и уведомлении в трее, но если Вы его не прочитали в течение отведенного времени, то программа могла отправить уведомление повторно. Чтобы этого не происходило — храним в памяти тело сообщения и, если дубль, то не показываем. Это решает проблему с постоянно всплывающими уведомлениями, когда юзеру тупо некогда ответить на сообщение (допустим, пишет срочное письмо, сценарий, отвечает клиенту). И не придётся постоянно жать на крестик.

    Разыгрываем в голове ситуацию — юзер отошел по своим делам. В это время пришло новое сообщение, появилось уведомление и исчезло спустя несколько секунд. Программа свёрнута и чат не виден. Хорошо, уведомление исчезло через пару секунд, значит, если юзер не отреагировал, то через пару секунд включаем ненадолго мерцающую подсветку иконки в панели задач. Моргнём два‑три раза и дальше будем просто светиться (не надо моргать почем зря, может юзеру не до чата, а так просто оранжевым светится иконка внизу и сильно глаз не мозолит). А если свернуто в трей? Тогда красная точка над иконкой в трее. И без всяких «99+» непрочитанных сообщений, это лишнее.

    (пока писал эту статью, решил, что нужна будет дополнительная настройка «Показывать уведомления поверх других окон» с возможностью отключения, а то вдруг юзер катает‑нагибает? Уведомление может перекрыть ему стратегически важную информацию. Сказано‑сделано)

Собираем билд…

  • Изначально была идея собрать всё в один.exe файл, вес которого был примерно 1–1,5 мб, и потреблял примерно 15 мб RAM. Это успех… но не всё оказалось так просто. Одна из нативных библиотек, написанная на c++ никак не хотела встраиваться. Это рушило «концепцию одного файла» на корню. Да и нужно было еще проработать дополнительную безопасность. Добавляем на всякий случай защиту от XSS‑атак, блокировку трекеров, антидебаггер (с которым хапаем проблем при тестировании и получаем невозможность запуска на виртуальных машинах), отслеживание контрольных сумм. Оставался открытым вопрос последующих обновлений. Понятно, что веб‑версия сама по себе новая при каждом запуске, но как быть с обновлением билдов самой программы? Накидав всяких фич по безопасности заметил, что потребление RAM значительно выросло, но не критично. А в моей RAM еще свежи воспоминания о чаяниях юзеров по поводу полной переустановки десктопного МАХ при каждом обновлении… так быть не должно!

    Подумав немного, решил использовать Velopack для обновлений. По итогу отказался от концепции «одна программа — один файл». Единственное — зашил парсер на javascript внутрь.exe, а то как‑то несекьюрно. Velopack помог решить несколько вопросов сразу:

  • Дельта‑обновления в фоне. Вышел новый билд? При запуске программы Вы получите уведомление о наличии обновлений. В случае согласия обновиться — даже глазом моргнуть не успеете, как программа получит обновления только новых файлов и быстро перезапустится. Только. Новых. Файлов. А не полный реинсталл, чем любят грешить некоторые девелоперы.

  • Пусть библиотеки не будут вшиты в.exe, зато при сборке нового билда и получении обновлённных библиотек юзеру будет проще обновиться с меньшими затратами на трафик.

  • Velopack сам контролит хэш файлов, так что эту функцию, как и несколько других, вырезал из исходного кода за ненадобностью.

  • Что не понравилось? Работа мессенджера в таком режиме потребляет RAM на уровне «телеги», скачками до 100–300 мб RAM. В среднем около 100 мб.

  • Вес установочного файла <10 мб. Пока только win‑x64. Пользуйтесь!

P. S.: У меня на гитхабе есть еще интересные штучки…

ссылка на оригинал статьи https://habr.com/ru/articles/1048178/