Как и было обещано, мы выпускаем под LGPL нашу библиотеку эмуляции эмулятора терминала linux, которую мы используем для показа консолей виртуальных машин в облаке. Называется она, соответственно, pyte (PYthon Terminal Emulator).
По нашим собственным оценкам, покрытие «текстового» функционала console_codes приближается к 100% (от 80 до 90%, как подсказывают пессимисты из числа оппортунистов среди разработчиков).
Не реализованы: коды загрузки шрифтов в знакогенератор VGA-адаптера, управление энергосбережением VESA, звуковая сигнализация (коды управления частотой и длительностью звука), управление палитрой, собственные чарсеты; в общем всё то, что не имеет отношения к тексту.
Зато реализованы все остальные сложные функции, такие, как блокировка регионов экрана для записи, скроллинга, управление режимами переноса строк, правильная обработка атрибутов при различных видов удаления текста и т.д. — всё то, что нужно существующим приложениям, таким как nano, adom (на картинке фрагмент ESC-кодов и получающегося изображения как раз из ADOM'а), vim, emacs, mc, aptitude, dialog, yast2 и т.д. для полноценной отрисовки.
Библиотека написана на питоне и заточена под удобство манипуляций над экраном, абстрагируясь от графического представления изображения, что позволяет её использовать в коде, осуществляющим дальнейшие преобразования (например, передачи экрана в JS или сериализации в БД).
Второй важной особенностью библиотеки является поддержка диффов (разниц) между предыдущим и текущим состоянием экрана. Это необходимо для экономной передачи изображения через каналы ограниченной скорости (читай, интернет) и отрисовки на устройствах ограниченной производительности (читай, javascript).
История создания
В начале была замечательная в своей наивности библиотека vt102. Она кое-как рисует часть esc-кодов vt102, совсем не задумываясь о unicode, тонких нюансах скроллинга регионов экрана, производительности и стабильности работы. Как о ней писал автор, она была предназначена для читинга в игре nethack, и не более.Начинали мы с неё. Некоторое время мы пытались исправлять ошибки и дорабатывать, но потом у нас оказалось, что во-первых vt102 не поддерживает некоторых кнопок (PgUp, например), а во-вторых… Как я писал раньше, главное достоинство терминала linux состоит в том, что его ожидает по-умолчанию linux.
Пришлось 'from scratch' реализовывать весь функционал linux console (с упомянутыми выше ограничениями на особенности последовательного порта по сравнению с VGA-адаптерами). Таким образом, библиотека плавно переименовалась с vt102 на pyte (Python Terminal Emulator).
Не смотря на то, что библиотека сейчас написана с нуля, мы решили её так же опубликовать под LGPL, в основном из уважения к автору vt102, код которого мы хоть тактично и удалили, но часть идей всё же использовали, например, концепцию диспетчера.
Внутреннее устройство
Библиотека состоит из классов screen и stream. Screen содержит в себе копию экрана (символы и атрибуты), Stream — конечный автомат, отвечающий за обработку ESC и (в особенности) CSI-последовательностей. Стриму кормится последовательность символов, причём, у нас предусмотрена ситуация, когда использующая библиотеку программа ничего не знает про «символы» и оперирует потоком байтов с настраиваемой кодировкой (incremental decoder, для того, чтобы не было странных квадратиков из-за разрыва на середине UTF-8 символа). В принципе, мы работаем не только с UTF-8, но и с другими кодировками. Мы этот функционал в облаке сейчас не используем, но для чистоты совести таки реализовали.
После съедания всей последовательности символов, формирующих CSI-последовательность (это особый класс ESC-последовательностей, начинающихся с кодов ESC [, после которых идут параметры и команда, например, ESC[1;31m генерирует красный жирный цвет тона). Каждый вывод генерирует то или иное событие (вывод символа, скроллинг и т.д.) для всех подписчиков, среди которых и сама библиотека, обрабатывающая эти события. Разумеется, в числе желающих могут быть и внешний код, например, таким образом мы узнаём о появлении новых символов и сообщаем их Java-скрипту в панельке управления.
Объекты внутри Screen хранятся как обычные объекты python. У нас была версия, использующая более быстрые сишные массивы, но мы наткнулись на некоторые затруднения с конвертацией между «удобным» для библиотеки форматом и массивом, так что производительность массивов была сильно смазана постоянными конвертациями. Кстати, использование змеиных объектов упрощает доступ к их потрохам и, главное, сериализацию в базу данных (что и является «киллер-фичей» нашей консоли, которая переживает перенос виртуальной машины между серверов без обрывов и обнуления содержимого экрана).
Кстати, эта библиотека замечательно работает под питоны с 2.6 по 3.2+ и даже под PyPy.
Планы на будущее
В ближайшей перспективе планируется дополнение библиотеки поддержкой скроллинга (то самое Shift-PgUp), которое, кстати, мы добавим и в наше облако.
Кроме того, есть мысль заняться немного бесполезным перфекционизмом и соответствовать стандартам лучше самой консоли линукса, то бишь проходить vttest без единой ошибки.
Вещь, которую мы пока не планируем (хотя с великим удовольствием примем коммиты) — это расширенная поддержка юникода — поддержка нормализации символов, символов разной ширины и т.д. В принципе, в питоне для этого всё есть — но у нас нет потребностей в подобном (пока мы не нацелились на азиатский рынок).
Если кому-то эта библиотека будет полезна, то мы будем благодарны за сообщения об использовании, багрепорты и рекламации.
Ссылки
easy_install pyte
github.com/selectel/pyte
Кому говорить спасибо?
bobry за код,
o_l и akme за согласие на публикацию под LGPL.