Вы наверняка знакомы с asciinema (github), это удобный опенсорсный инструмент для записи действий в терминале. Записи сохраняются в простом для чтения текстовом формате, поэтому весят совсем немного, а веб-плеер по сути воспроизводит текст из терминала вместо видео, так что любой кусок можно скопировать и использовать. Готовый материал можно загрузить в одно нажатие на asciinema.org или сначала отредактировать локально. Плеер можно встроить на сайт буквально в три строки, бонусом прилагаются всякие плюшки с оформлением и совместимостью, и вообще по совокупности всех фич (и отсутствия головной боли) asciinema давно перерос все аналоги. Вот только есть несостыковка: записи в проекте называют asciicasts, по аналогии со скринкастами — но возможности стримить сессию в реальном времени не было несколько лет, пока не вышел релиз 2.0, в котором с помощью нового формата файлов удалось реализовать на удивление стабильную и удобную раздачу на любой терминал в реал-тайме. О том, как это работает, о подводных камнях и перспективах — под катом.
Один формат — много возможностей
В старых версиях данные записывались в JSON, что добавляло немало оверхеда, да и парсинг у него нетривиальный, а главное, объект неудобно дробить на чанки для частичной передачи и чтения данных. На смену пришёл кастомный формат:
{"version": 2, "width": 236, "height": 54, "timestamp": 1613998795, "idle_time_limit": 1.0, "env": {"SHELL": "/bin/bash", "TERM": "screen"}}
[0.023635, "o", "client@some-desktop:~$ "]
[0.812065, "o", "h"]
[1.087183, "o", "e"]
[1.246706, "o", "l"]
[1.473065, "o", "l"]
[1.657363, "o", "o"]
[4.114169, "o", "exit\r\n"]
В первую строку записываются метаданные и параметры воспроизведения, в каждую последующую — очередная строка терминала. На вид очень похоже на JSON, но теперь можно отображать любую строку по отдельности, добавив к ней метаданные. Теперь можно не только передавать данные по частям, но и дописывать новый каст в конец старого файла.
Если раньше единственным способом синхронного вывода было перенаправление записи в stdin второго терминала, что подразумевало хранение всего каста в памяти и воспроизведение после полного получения и парсинга, то теперь воспроизведение начинается сразу после анализа первой строки. Поток можно, например, завернуть в юниксовый именованный канал:
mkfifo /tmp/demo.pipe
# viewing terminal
asciinema play /tmp/demo.pipe
# recording terminal
asciinema rec /tmp/demo.pipe
Или можно передавать данные по сети с помощью netcat:
# viewing terminal (hostname: node123)
asciinema play <(nc -l localhost 9999)
# recording terminal
asciinema rec >(nc node123 9999)
Причём на принимающей стороне необязательно даже иметь установленный asciinema, с режимом --raw данные отправляются «как есть», без конвертации. Но там не будет метаданных, не будут сохранены тайминги и задержки, поэтому такой вариант не слишком привлекателен. Гораздо лучше шагнуть ещё дальше и стримить сессию по ssh! Но здесь лучше не торопиться и сначала разобраться в реализации.
Рисуем картинку локально
Установка asciinema:
sudo apt install python3-pip
sudo pip3 install asciinema
Запишем тестовый файл командой
asciinema rec -i 1 file.cast
. -i 1
— это параметр, обрезающий задержку при вводе до одной секунды.Пример файла каста выше соответствует выводу
cat file.cast
, он статичен. Но если начать запись и в соседней вкладке запустить tail -f file.cast
, строки будут появляться по мере дописывания в файл после изменений в терминале. Этот динамически обновляющийся вывод можно перенаправить в asciinema play
: # принимающая вкладка
tail -fn +1 file.cast | asciinema play -
Таким нехитрым образом мы запускаем зеркальное отображение наших действий в записываемой вкладке. Но картинка будет соответствовать источнику только если плеер изначально принял первую строку с параметрами (в частности,
-i
) и успел «догнать» стрим. Чтобы избежать проблем с задержкой просто будем передавать вместе с последней строкой первую: # принимающая вкладка
(head -1 file.cast && tail -fn 0 file.cast) | asciinema play -
К сожалению, при этом ломается первая строка в «зеркале» — она начинается сразу с введённых символов, опуская префикс, но это не критично, да и достаточно одного переноса, чтобы всё вернулось:
В целом, для простых юзкейсов можно не запариваться head'ом, но если строить полноценную систему с подключением посередине стрима и восстановлением после обрыва соединения, конечно, передавать первую строку нужно обязательно.
Переносим отображение на удалённый сервер
Нам понадобится беспарольный доступ, поэтому в принимающей вкладке генерируем ключи RSA, добавляем публичный ключ на сервер и идём его настраивать:
ssh-keygen -t rsa
ssh-copy-id -i ~/.ssh/id_rsa.pub user@hostname
ssh user@hostname
# на сервере поставим также утилиту pv для буферизации
sudo apt install python3-pip pv
sudo pip3 install asciinema
После установки осталось перенаправить поток текста в файл на сервере:
# клиент
asciinema rec -i 1 >(ssh user@hostname tee /path/to/file.cast >/dev/null)
# сервер
tail -fn +1 /path/to/file.cast | asciinema play -
Готово! По сути, всё уже работает. Но стоит добавить ещё пару штрихов: во-первых,
asciinema play
— высокоуровневая команда, для которой можно определить скорость выполнения операций. Чем выше значение (опционального) параметра -s
, тем меньше задержка и выше нагрузка. Для наших целей куда лучше подойдёт asciinema cat
, который работает на запись как аналог режима --raw
, но воспроизводится с сохранением метаданных и параметров. Кроме того, воспользуемся pv
для создания буфера на случай скачков производительности или сетевых лагов: # сервер
tail -fn +1 /home/benaryorg/.local/tmp/tmp.6nkIacxYqF/foo | pv -q -b 8m | asciinema cat -
Результат
Плеер не встраивается в Хабр, извините
Светлое будущее
Вообще вся эта чудесная функциональность появилась довольно давно: 2.0 вышел около трёх лет назад. Однако, хорошая новость в том, что весь предыдущий год команда asciinema-player переписывала плеер целиком чтобы добавить в него вебсокеты, event sourcing и полностью сделать его совместимым с настоящими скринкастами. И хотя в профильном issue нет активности с весны, по коммитам видно, что работа кипит. Будет очень интересно посмотреть на стриминговый сервис для воинов консоли, не находите?
На правах рекламы
Подыскиваете VDS для отладки проектов, сервер для разработки и размещения? Вы точно наш клиент :) Посуточная тарификация, создавайте собственный конфиг в несколько кликов.