О чем эта статья?

Эта секция написана уже после статьи, чтобы читатель посмотрел, а надо ли ему что-то отсюда или нет, но это забавное приключение (напоминаю, что статьи в форме (б|в)лога, как всегда.

Что будет ниже:

  • Поиск open source решения для общения голосом, шаринга экрана, включения видео и чатов в режиме peer-to-peer, без лишних бекендов

  • Запуск этого решения в открытую в github pages

  • Заворачивание этого решения на приватный сервер

  • Простенькое закрытие доступа туды через http basic authentication

  • Заключение с описанием некоторых замечаний и потенцевальных возможностей

Зачем?

Типичное проприетарное решение, которое не дает вам пользоваться всеми преимуществами коммуникации

В продолжении к первой публикации про старт инди-дев-(б|в)лога, в котором поделился первыми шагами по созданию кроссплатформенного решения, я понял, что мне негде его обсуждать, а значит нужен добротный, как гнедой конь, решение по коммуникации.

Звонки в raidcall, skype, teams, mattermost, google chat, slack, jabber и телеге звучат безумно, особенно, когда нужно быстро подключиться, пошарить экран, а самое главное — не думать о том, что шаришь кому-то телеметрию за проприетарное 3rd-party.

Когда ведешь лекции, особенно бесит, что дискорд блочит screen sharing, когда там юзеров >25, а в гугл мит есть лимит по времени.

Разумеется, читатель имеет право предъявить за проприетарные ОС, браузеры и прочие ПО, либо, что мне просто лень платить, но скорее просто хочется поискать велосипедов, да и поделиться с вами, что накопал и начал юзать.

Как и говорилось ранее, я попытался придумать оправданий для велосипедов, едем-те.

Гуглим какой-нибудь open source

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

И находим там всякий хлам, ищем дальше, конкретизируя запросы

Спустя полчаса поисков, находим какое-то более менее звучащее решение

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Читаем ридмик, и видим, что в целом удовлетворяет

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Надо пойти посмотреть демку – https://chitchatter.im/

Выглядит более чем достаточно, переходя по кнопкам находим, что есть: mardkown-based чат, видео, аудио, шаринг экрана и файлов

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

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

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Находим упоминания rtc, а самое главное trystero

import { joinRoom as trysteroJoinRoom, Room, BaseRoomConfig } from 'trystero'  export const joinRoom: typeof trysteroJoinRoom = (   _config: BaseRoomConfig,   _roomId: string ) => {   const room: Room = {     makeAction: () => [() => Promise.resolve([]), () => {}, () => {}],     ping: () => Promise.resolve(0),     leave: () => {},     getPeers: () => ({}),     addStream: () => [Promise.resolve()],     removeStream: () => {},     addTrack: () => [Promise.resolve()],     removeTrack: () => {},     replaceTrack: () => [Promise.resolve()],     onPeerJoin: () => {},     onPeerLeave: () => {},     onPeerStream: () => {},     onPeerTrack: () => {},   }    return room }  export const selfId = ''

Копаем про этого зверя и находим репу trystero, а с ним и вебсайт, обещающий сделать любое решение мультиплеером — https://oxism.com/trystero/

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Читаем и понимаем, что это какая-то шляпо про

Trystero can connect peers via 🌊 BitTorrent, 🐦 Nostr, 📡 MQTT, 🪐 IPFS, and 🔥 Firebase.

Посидел, покурил, не понял, думаю комментаторы лучше объяснят, почему для https://en.wikipedia.org/wiki/Session_Description_Protocol нужен торрент, жду объяснений в комментариях. Учитывая, что все обещают зашифрованный трафик, вроде как звучит норм.

Решение найдено, теперь внедряем

Форк

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Просто делаем форк основного репозитория отседа

И идем его настраивать:

  • Вырубаем ненужные странички (Wikis, Issues, Projects), и идем сразу же конфигурировать все необходимое из секции self-hosted

    Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

  • Включаем удаление веток, оставляем только Rebase flow (почему? пишите нормальные коммиты, не храните PRs дольше 1-2 дней, и будет вам счастье)

    Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Судя по README, нужно сделать две вещи:

  • Поменять homepage в package.json, чтобы приложение резолвило к себе статику

  • Указать DEPLOY_KEY (как же бесит постоянна вакханалия вокруг обслуживания ключей в очередном github action

Начну со второго, так как сначала надо проверить, что оно запускается само

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Локально генерим ключики

ssh-keygen -t rsa -b 4096 -C "$(git config user.email)" -f gh-pages -N ""

Топаем сюды — settings → deploy keys → add new

Пишем в Title: DEPLOY_KEY
Пишем в Key: значение сгнерированного публичного ключа: cat gh-pages.pub
Ставим галочку возле Allow write access

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Потом идем в — secrets → actions → new repository secret, и делаем тоже самое, только вставляя приватный ключ: cat gh-pages

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Судя по action-у, оно будет тригерриться только при пуше в main и в github pages, а значит надо создать main ветку и сделать её главной

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Топаем в ветки и создаем main

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Затем топаем в настройки репозитория и ставим main главной веткой

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Дальше пытаемся понять почему не запустились actions и находим, что надо было разрешить actions у форкнутой репы

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Соглашаемся и триггерим action для деплоя в gh-pages

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Примерно полторы минуты, оно прошло

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Справа Code-странице репозитория появляется инфо про github pages

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Кликаем туда и находим ссылку на инстанс по клику на иконку возле 1 minute ago

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Работать оно работает, вот только статику не отдаёт, но это не важно, так как статика просто не там лежит

Оно ищет под https://the-homeless-god.github.io/assets/index-OD1TD8_t.js

А вот часть github pages оно пропустило в рамках homepage

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

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

Так что 1 раз пушим в мастер редактирование в package.json поля homepage на ссылку на наш github page

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Коммитим и ждем как пройдет пайплайн

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Помогло? Нет.
Идем в vite.config.js и указываем ему base

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Запустилось, потыкался, ок

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Пойду открою им PR в README хоть, пусть про base напишут

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

А теперь мы хотим это тащить на приватный сервер

А почему? А зачем? Оно же итак работает из-под github pages, но вот что важно — а я не хочу чтобы туда кто-то имел доступ

Берите тачку где хотите, мне нравятся ruvds, digitalocean и из самых бюджетных — это justhost.

Берите бубунту (осуждаю, но для статьи на хабре пойдет).

На этой самой бубунте:

  • Создайте отдельного юзера и папку под нашу статику, ну и права отдайте

    adduser ga mkdir -m 755 /var/www/chat chown ga:ga /var/www/chat su -- ga mkdir /home/ga/.ssh/   ssh-keygen -t rsa -b 4096 -C "deployer" -f deployer -N ""

    И пишем публичный ключик в authorized_keys

  • Поставьте nginx и настройте конфиг смотреть на статику

    # устанавливаем nginx apt install nginx  # говорим firewall чтоб разрешал ваш nginx, ssh и http/https ufw allow ssh ufw enable ufw allow http ufw allow https ufw allow 'Nginx HTTP'
  • И редачим конфиг: vim /etc/nginx/nginx.conf

    server { 	access_log /var/log/nginx/access.log;      add_header X-Xss-Protection "1; mode=block" always;     add_header X-Frame-Options SAMEORIGIN;     add_header X-Content-Type-Options nosniff;     add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;      root /var/www/chat;     index index.html;      location / {       try_files $uri $uri/ /index.html;     } }

В настройках репозитория добавляем три новых ключа:

  • SERVER_HOST – адрес нашего сервака

  • SERVER_USERNAME – имя юзера

  • SERVER_SSH_KEY – содержимое приватного ключа

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

И дописываем deploy-логику

 # тут мы собс-на просто смотрим, что сервер жив и радуемся   - name: agent - get server status     uses: appleboy/ssh-action@master     with:       host: ${{ secrets.SERVER_HOST }}       username: ${{ secrets.SERVER_USERNAME }}       key: ${{ secrets.SERVER_SSH_KEY }}       script: neofetch && df -H / && free -m  	# тут мы ставим на github action ssh ключ, чтобы можно было пользоваться всякими командами а-ля rsync, scp и прочее   - name: agent - install ssh key     uses: shimataro/ssh-key-action@v2     with:       key: ${{ secrets.SERVER_SSH_KEY }}       known_hosts: unnecessary    # тут мы его устанавливаем   - name: agent - install ssh     run: ssh-keyscan -p 22 -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts    # подчищаем за собой директорию на сервере   - name: agent - cleanup static folder     uses: appleboy/ssh-action@master     with:       host: ${{ secrets.SERVER_HOST }}       username: ${{ secrets.SERVER_USERNAME }}       key: ${{ secrets.SERVER_SSH_KEY }}       script: rm -rf /var/www/chat/**    # деплоим статику на сервер   - name: agent - deploy static     run: ls -la ./dist && rsync -avz -r -e "ssh -p 22" ./dist/ ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_HOST }}:/var/www/chat/    # смотрим, что статика действительно там   - name: agent - show deployed dir     uses: appleboy/ssh-action@master     with:       host: ${{ secrets.SERVER_HOST }}       username: ${{ secrets.SERVER_USERNAME }}       key: ${{ secrets.SERVER_SSH_KEY }}       script: ls -la /var/www/chat/

Коммитим это всё и ждём

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Прячем за basic http authentication

Подробнее тут

# Ставим либу apt install apache2-utils  # Генерим пользователя + пароль htpasswd -c /etc/apache2/.htpasswd ga  # Смотрим, что всё хорошо cat /etc/apache2/.htpasswd

Дальше в nginx.conf пишем чтобы доступов не было

auth_basic           "Administrator’s Area"; auth_basic_user_file /etc/apache2/.htpasswd;

Получится что-то вроде

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Перезапускаем Nginx + дописываем себе генерацию серта откуда-нибудь, будь-то Let’s Encrypt

systemctl nginx restart

И теперь когда вы перейдете по ip своего сервера будет окошко с запросом логина и пароля

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Остаётся только убирать налету информацию про ip адрес в homepage в package.json и удалить содержимое vite.config.ts про base

Получится примерно так:

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

Мы просто удаляем строку с помощью sed, а для подмены содержимого homepage поля используем встроенные методы и пересобираем

Заключение

Теперь у вас как и у меня есть свой спрятанный на сервере клиент для коммуникации без проприетарного бугага.

Может быть вы что-то накоммуниздите здесь полезного для себя, а может что-то напишите тут на улучшение.

Допустим вы решили коммерциализировать это решение, но оно по лицензии к вам не подходит?

Вы можете написать адаптер который вклинивается в этот код с вашими дописками хоть из-под другого npm пакета, хоть из-под git submodule.

Из ограничений у этого клиента — 256 участников в вашей комнате

Развертываем peer-to-peer чат с голосом, видео, шарингом экрана, файлов и паролем

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

Среди прочего, упустил немногое про бубунту, просто потому что ну не люблю я её, используйте BSD.

А в остальном — ничего нигде не хранится, всё шифруется, да и всё бесплатно, если не нужно приватить доступ к статике. И можно вести лекции не боясь, что качество просядет и общаться с коллегами используя максимальный стриминг.

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

Have a fun!