Средства измерения программ на Go

Гофер с лупой

В этой статье я хотел бы поделиться способом профилирования и трассировки программ на Go. Я расскажу, как можно это делать, сохраняя код гибким и чистым.

TL;DR

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

Другими словами, логирование и сбор метрик – это подмножества трассировки.

Шаблонный код трассировки может быть сгенерирован с помощью gtrace.

Проблема

Предположим, что у нас есть пакет lib и некая структура lib.Client. Перед выполнением какого-либо запроса lib.Client проверяет соединение:

package lib  type Client struct {     conn net.Conn }  func (c *Client) Request(ctx context.Context) error {     if err := c.ping(ctx); err != nil {         return err     }     // Some logic here. }  func (c *Client) ping(ctx context.Context) error {     return doPing(ctx, c.conn) }

Что делать, если мы хотим делать запись в лог прямо перед и сразу после того, как отправляется ping-сообщение? Первый вариант – это внедрить логгер (или его интерфейс) в Client:

package lib  type Client struct {     Logger Logger      conn net.Conn }  func (c *Client) ping(ctx context.Context) (err error) {     c.Logger.Info("ping started")     err = doPing(ctx, c.conn)     c.Logger.Info("ping done (err is %v)", err)     return }

Если мы захотим собирать какие-либо метрики, мы можем сделать то же самое:

package lib  type Client struct {     Logger  Logger     Metrics Registry      conn net.Conn }  func (c *Client) ping(ctx context.Context) (err error) {     start := time.Now()     c.Logger.Info("ping started")      err = doPing(ctx, c.conn)      c.Logger.Info("ping done (err is %v)", err)     metric := c.Metrics.Get("ping_latency")     metric.Send(time.Since(start))      return err }

И логирование, и сбор метрик – это методы трассировки компонента. Если мы продолжим увеличивать их количество внутри Client, то скоро обнаружим, что бóльшая часть его кода будет содержать код трассировки, а не код его основной функциональности (который заключался в одной строчке с doPing()).

Количество несвязных (не связанных с основной функциональностью Client) строчек кода это только первая проблема такого подхода.

Что, если в ходе эксплуатации программы вы поймете, например, что имя метрики нужно поменять? Или, например, вы решите поменять логгер или сообщения в логах?

С таким подходом как выше, вам придется править код Client.

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

Что, если вы переиспользуете код Client между разными программами? Или, более того, выложили ее в общий доступ? Если честно, то я советую рассматривать каждый пакет в Go, как библиотеку, даже если в реальности используете её только вы.

Все эти вопросы указывают на ошибку, которую мы совершили:

Мы не должны предполагать, какие методы трассировки захотят применять
пользователи нашего кода.

Решение

На мой взгляд, правильно было бы определить точки трассировки (или хуки), в которых могут быть установлены пользовательские функции (или пробы).

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

Такой подход используется, например, в пакете httptrace из стандартной библиотеки Go.

Давайте предоставим такой же интерфейс, но с одним исключением: вместо хуков OnPingStart() и OnPingDone(), мы определим только OnPing(), который будет возвращать callback. OnPing() будет вызван непосредственно перед отправкой ping-сообщения, а callback – сразу после. Таким образом мы сможем сохранять некоторые переменные в замыкании (например, чтобы посчитать время выполнения doPing()).

Client теперь будет выглядеть так:

package lib  type Client struct {     OnPing func() func(error)     conn net.Conn }  func (c *Client) ping(ctx context.Context) (err error) {     done := c.OnPing()     err = doPing(ctx, c.conn)     done(err)     return }

Выглядит аккуратненько, но только если не проверять хук OnPing и его результат на nil. Правильнее было бы сделать следующее:

func (c *Client) ping(ctx context.Context) (err error) {     var done func(error)     if fn := c.OnPing; fn != nil {         done = fn()     }     err = doPing(ctx, c.conn)     if done != nil {         done(err)     }     return }

Теперь наш код выглядит хорошо в плане SRP принципа и гибкости, но не так хорошо в плане читаемости.

Прежде чем это исправить, давайте решим еще одну проблему трассировки.

Объединение хуков

Как пользователи могут установить несколько проб для одного хука? Пакет
httptrace содержит метод ClientTrace.compose(), которыйnобъединяет две структуры трассировки в одну. В результате каждая функцияnполученной структуры делает вызовы соответствующих функций в паре родительских структур (если они были установлены).

Давайте попробуем сделать то же самое вручную (и без использования пакета reflect). Для этого мы перенесем хук OnPing из Client в отдельную структуру ClientTrace:

package lib  type Client struct {     Trace ClientTrace     conn net.Conn }  type ClientTrace struct {     OnPing func() func(error) }

Объединение двух таких структур в одну будет выглядеть следующим образом:

func (a ClientTrace) Compose(b ClientTrace) (c ClientTrace) {     switch {     case a.OnPing == nil:         c.OnPing = b.OnPing     case b.OnPing == nil:         c.OnPing = a.OnPing     default:         c.OnPing = func() func(error) {             doneA := a.OnPing()             doneB := b.OnPing()              switch {             case doneA == nil:                 return doneB             case doneB == nil:                 return doneA             default:                 return func(err error) {                     doneA(err)                     doneB(err)                 }             }         }     }     return c }

Достаточно много кода для одного хука, верно? Но давайте двигаться дальше, чуть позже мы вернемся к этому.

Теперь пользователь может менять методы трассировки независимо от нашего компонента:

package main  import (     "log"      "some/path/to/lib" )  func main() {     var trace lib.ClientTrace      // Logging hooks.     trace = trace.Compose(lib.ClientTrace{         OnPing: func() func(error) {             log.Println("ping start")             return func(err error) {                 log.Println("ping done", err)             }         },     })      // Some metrics hooks.     trace = trace.Compose(lib.ClientTrace{         OnPing: func() func(error) {             start := time.Now()             return func(err error) {                 metric := stats.Get("ping_latency")                 metric.Send(time.Since(start))             }         },     })      c := lib.Client{         Trace: trace,     } }

Трассировка и контекст

Трассировка кода так же может происходить в зависимости от контекста. Давайте предоставим пользователю возможность связать ClientTrace с экземпляром context.Context, который потом может быть передан в Client.Request():

package lib  type clientTraceContextKey struct{}  func ClientTrace(ctx context.Context) ClientTrace {     t, _ := ctx.Value(clientTraceContextKey{})     return t }  func WithClientTrace(ctx context.Context, t ClientTrace) context.Context {     prev := ContextClientTrace(ctx)     return context.WithValue(ctx,         clientTraceContextKey{},         prev.Compose(t),     ) }

Фух. Кажется, мы почти закончили!

Но не кажется ли утомительным писать весь этот код для всех компонентов?

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

Хорошая новость состоит в том, что весь код для объединения хуков, проверок на nil и функций для работы с контекстом весьма шаблонный, и мы можем его сгенерировать без использования макросов или пакета reflection.

github.com/gobwas/gtrace

gtrace это инструмент командной строки для генерации кода трассировки из примеров выше. Для описания точек трассировки используются структуры, помеченные директивой //gtrace:gen. В результате вы получаете возможность вызова хуков без каких-либо проверок на nil, а так же функции для их объединения и функции для работы с контекстом.

Пример сгенерированного кода находится здесь.

Теперь мы можем удалить весь рукописный код и оставить только это:

package lib  //go:generate gtrace  //gtrace:gen //gtrace:set context type ClientTrace struct {     OnPing func() func(error) }  type Client struct {     Trace ClientTrace     conn net.Conn }  func (c *Client) ping(ctx context.Context) (err error) {     done := c.Trace.onPing(ctx)     err = doPing(ctx, c.conn)     done(err)     return }

После выполнения команды go generate мы можем использовать сгенерированные не экспортированные версии хуков из ClientTrace.

Вот и все! gtrace берет весь шаблонный код на себя и позволяет вам сфокусироваться на точках трассировки, которые вы хотели бы предоставить пользователям для измерения вашего кода.

Спасибо за внимание!

References

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

Как нарисовать кота

Это мой доклад на PiterPy Meetup #20, записанный текстом и слегка отредактированный. Если вам захочется смотреть, а не читать, видео есть в конце поста

Привет, Хабр. Я расскажу про то, как ценно, на мой взгляд, не только владеть своими привычными рабочими инструментами, но и всякими штуками, что лежат вокруг.

Заголовок поста — как нарисовать кота. Это кликбейтная уловка, рисуйте котов как вам угодно! Но тема реально меня волнует. Сейчас всё объясню, а по дороге упомяну T-shaped skills, сам Хабр и три личных истории.



Я СТО в питерском стартапе. Тут наверняка найдутся те, кто пользовался или слышал про мои продукты, но сегодня я говорю совсем о другом.

Для начала про букву Ти. Может показаться, что это русская буква Тэ, как во фразе “тут нет кота”, но это не Тэ, это Ти из T-shaped skills. Это метафора, которую придумали ещё в восьмидесятом году, она наглядная и этим очень мне нравится.

Вот есть у нас джуниор-разработчица Ася, и, разумеется, у Аси есть какой-то скилл.

Ася пишет микросервисы. Асина работа выглядит как-то так: Ася пишет эндпоинт, на эндпоинт прилетает запрос, и асина задача, чтобы сервис сделал запрос в базу и выдал разумный ответ.

Ася очень беспокоится и на всякий случай каждый раз проверяет на Stack Overflow, правильно ли она объявила пустой список.

Проходят месяцы, задачи меняются, знающие коллеги уходят в отпуска, приходится учиться, да и самой любопытно. И вот Асин скилл подрос. Теперь она наизусть помнит как пишется import werkzeug и пугает этим словом своего кота.

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

Обозначим это на нашей схеме. У Аси был скилл, и скилл вырос. Такое состояние навыков, как в момент у Аси, в метафоре T-shaped skills называют Ай.

Ай это примерно как Ти, но с некоторым отличием.

В нашей метафоре это значит, что кроме экспертного знания в своей области, есть и смежные области, в которых Ася может развиваться.

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

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

Первая моя история называется “kubectl apply minus f foo dot yaamel”

Начинается она так. Я читаю Хабр. Алгоритм чтения Хабра у меня очень простой, где-то раз в месяц я открываю лучшее за месяц, и смотрю что попадёт на первую страницу. Очень радуюсь, если вижу пост Сергея Абдульманова под юзернеймом Milfgard, или пост Zelenyikot (кодовое имя Виталий Егоров).

В тот раз я увлечённо читал про Кубернетес, всякие там поды, ноды и обезьянку хаоса — обезьянка хаоса это скрипт, который специально выключает случайные куски вашей инфраструктуры, а сервис должен выстоять.

Мне было очень любопытно. Во первых я понимал, что если выключить любой из наших серверов, сервис ляжет. Во вторых меня чуть беспокоило, что тайное знание как всю нашу инфраструктуру настроить и сконфигурировать лежит у меня в голове.

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

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

Я поставил minikube, это штука, чтобы запустить Кубернетес у себя на ноуте, и радостно прошёл туториал. У меня горели глаза. Я веселился. Вместо задач я играл с туториалом. Мне было классно, я учился новому, я становился более ценным специалистом, и к тому же обманывал сразу двух жаб. Да, жаб. С жабами я вас сейчас и познакомлю.

Первую жабу зовут Жаба Прокрастинации. Вроде бы прикольно изучить этот ваш Кубернетес, но не сейчас. Занесу в список штук, которые неплохо бы выучить. Вон там уже 53 пункта с пометкой важно накопилось. Ох и тяжело же в наше время разработчикам, столько всего, столько всего.

Вторую жабу зовут Жаба Перфекционизма. Кубернетес если уж знать, так знать хорошо. Это нужно с основ начинать. Толстый томик купить, прочитать, вести конспект. Подчёркивать определения маркером. Всё подчёркнутое выучить наизусть. Я хороший специалист, я мастер своего дела, если я и изучаю кубернетес, то уж точно смогу на доске все варианты StrategyType для деплоймента выписать. Я не раздолбай, а мастер своего дела, урывками учиться не буду. Вот пойду книжку закажу. И в список штук для изучения добавлю. Вон там уже 53 пункта с пометкой важно накопилось. Ох и тяжело же в наше время разработчикам, столько всего, столько всего.

Так вот. На чём мы остановились. Пока я ставил minikube и радостно проходил туториал, я этих жаб элегантно обманывал. Я веселился, я играл, жаб не интересует баловство и дурачество, оно невидимо для них. А прогресс такой, словно по-настоящему учишься. Я потыкал Kubernetes ещё, туториалы скучные, задался вопросом, а как это засунуть в него реальный веб-сервер на джанго. Тaк-так, тут что-то про вольюмы, про stateful и stateless. Интересно. И, кажется, получилось. Жабы удивлены, возмущены и повержены.

Через несколько дней я вернулся к игре с Кубернетесом. Развил интуицию, перенёс один не особо значимый, но уже рабочий сервис. Порадовался. Тут надо сказать, что инфраструктура наша и так была в облаках, и не обошлось без ангелов. Ангелом нашим были Диджитал Оушн.

Диджитал Оушн это очень известный хостер, и в том числе он занимается поддержкой стартапов. Для нашей компании они выделили тридцать тысяч виртуальный диджитаоуновских долларов, которые можно потратить на аренду сервисов. Это реально большая поддержка, около двух миллионов рублей, спасибо им огромное.

Но были и ограничения:
►Нельзя майнить крипту
►Нельзя использовать сервера для машинного обучения
►И, самое важное, через год бесплатные деньги сгорают

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

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

Мы всё перенесли от одного хостера на другой, только поправив конфиги. Мне очень помогло, что я баловался с kubernetes.

Вторая моя история называется “Oculus”

Я очень люблю VR, у меня сразу два шлема от oculus, оба портативные, Quest и Go.

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

Мне было весело и по дороге я узнал уйму всего про шейдеры, web-стандарты и реалистичные структуры бетона. Это сделало меня более ценным профессионалом, но совсем не воспринималось как корпение над документацией. Мне было классно, я учился новому, я становился более ценным специалистом, и к тому же обманывал сразу двух жаб. С жабами вы уже знакомы, так что на время оставим их в покое, а я пока добавлю немного питона.

В другой своей игрушке я сделал так, что ты в VR шлеме ходишь и видишь других людей в шлемах.

Видишь их реально там, где они находятся. А ещё видишь двери, пол, стены, и вообще всё, что захочешь переместить из реального мира в виртуальный. Можно не видя друг друга и не снимая шлемов поиграть в ладушки. Это моя любимая часть.

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

Тут совершенно ничего не разобрать, но вот мой ноут, и на мониторе 3d-мир, желтые кубы — головы реальных людей в vr-шлемах, эти люди видят только пол, проём двери и друг друга. И пытаются так гулять. А а я смотрю на них в реальном времени в обоих мирах, снимаю видео, и отлично провожу время.

В книге Остина Клеонта «Кради как художник» творчество — это вовсе не свобода без ограничений. Все совсем наоборот. Преодолеть творческий ступор довольно просто — нужно ограничить самого себя. Уверен, что не он это придумал, но захотелось сослаться на бо́льшего эксперта.

Пост, напомню, называется “Как нарисовать кота”. Вот один из способов сделать это. Нарисовать его на CSS.

Для меня рисование CSS это как головоломки. Как очень маленьким набором инструментов что-то нарисовать? Инструментами, предназначенными не для рисования.

Будет забавно, а ещё вы узнаете примерно миллион новых свойств, а в более скучных задачах уровня “подвинуть div” будете себя чувствовать как рыба в воде.

Пиксель-арт это огромный мир, но я скажу о нём только потому что у сайтов есть фавиконки. Попробуйте сделать хорошо выглядящий фавикон 16×16. Это челлендж!

Я много лет назад работал в компании 220 вольт и попробовал, из интереса, нарисовать для интернет-магазина новый фавикон. Я отлично провёл время рисуя, и совсем не чувствую, будто потратил время зря, не смотря на то, что его не взяли (и правильно!). Спустя много лет у них всё тот же, не мой, желтый треугольник на фавиконе, и мне приятно на него посмотреть и вспомнить про суровый мир 16х16.

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

Я вижу четыре весомых пункта, зачем абстрактному IT специалисту могут пригодиться подозрительно похожие на работу развлечения. И это не считая войны с жабами:

►Гибкость как профессионала. Всё меняется, чтобы быть востребованным на рынке ценно уметь разное и смежное
►Путь в архитекторы, если вы, вдруг, хотите быть архитектором
►Это весело. Занятие делами, похожими на работу, но не работой — отличный отдых.
►Можно соединять ваши скиллы с другими областями. В не IT-сферe умение программировать это супер-способность.

Если вы быстро-быстро скроллите статью, то вы едва ли прочитаете это предложение, но зато увидите картинку

Подробнее про супер-способность. Есть вот 3D графика. У Blender, это такой софт для моделирования, есть python API. Может вы и не умеете рисовать в 3d, но вы можете за пару вечеров запрограммировать анимацию гиперкуба и отлично провести время.


Автор картинки programagor

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

Я составил список конкретных штук, которые можно поделать, если вам вообще хочется, но непонятно с чего начать

►Микроэлектроника и умный дом
►3D графика в Blender
►Персональный телеграм бот
►Функциональное программирование
►Клеточные автоматы
►Исследовать свой граф друзей по API соцсетей
►Нейросети, если вы ещё не
►Игрушки, см. фреймворк pygame
►Веб-сервис, который никто не сделает, кроме вас
►Процедурный ASCII арт

Вот так растёт скилл в том мире, который я описал, но есть и другие варианты. Например, вы можете быть экспертом в двух совсем разных областях, и их пересечение сделает вас уникальным супер-редким специалистом. Это классно, это значит, что у вас супер-уникальная компетенция. Но не будем на этом подробно останавливаться, есть более важный вопрос:

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

Для меня работает только одно. Помещайте это время не в категорию полезно, не в категорию личностный рост, а в категорию фан, отдых и веселье. Только так это получится. Может помочь играть с такими штуками с кем-то вместе, в рамках социализации. В духе, “эй, а не хочешь за вечерок игрушку вдвоём напишем?”. Можно думать об этом как о штуке для работы над личным брендом, типа “побалуюсь с демкой, потом расскажу на митапе”. Но только умоляю вас, ни в коем случае не кладите веселье в категорию “ещё один пет-проджект”, так ничего не получится. Это фан, это веселье, это как серия сериала, если вы смотрите сериалы, такое недопустимо оставлять умирать среди пет-проджектов.

Итак, чтобы это стало частью вашей и так занятой жизни, помещайте это время не в категорию полезно, не в категорию личностный рост, а в категорию фан. Только так это сработает.


На этом всё, спасибо, что прочитали, присылайте котов в лс, и вот видео оригинального доклада:

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

Безопасный доступ к умному дому при отсутствии публичного IP (часть 1)

Вступление

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

Есть «умный дом». В моем случае это безвентиляторный домашний сервер с ioBroker, хотя это не принципиально. Помимо домашних штучек хочется к нему цеплять датчики извне (например, на ESP32 из удаленной теплицы). Это решил делать через mqtt. Доступ к интерфейсу из Интернета.

Обычное дело. Но есть нюансы:

  • У провайдера нет возможности дать мне публичный IP адрес. И других провайдеров нет.
  • Не люблю привязку к конкретным облачным сервисам. Внешний сервис и закрыться может (как недавно gbridge уведомление прислал). И просто в случае отказа не понятно, что делать. Предпочитаю свое, что можно в случае чего перенести, переделать малой кровью.
  • Безопасность важна. Не паранойя, но выставить ioBroker в Интернет, особенно с учетом, что там выставляется несколько сервисов (flot…). Нет уж.

Дальше хочу показать не сразу результат, а процесс. Как шел, как трансформировались хотелки, менялись решения. Вполне возможно, что некоторые моменты можно решить более правильно/эффективно (я не сисадмин, не разработчик). А может кто-то не пойдет так далеко, и воспользуется промежуточным решением, которое я, к примеру, счел недостаточно для себя безопасным или удобным. Собственно, описанное в этой части — вполне рабочий вариант, но для меня «промежуточный».

Публичный адрес для mqtt

Дома публичного IP на роутере не светит (я не про фиксированный, это решаемо через dyndns и аналоги), а именно провайдер дает 10.х.х.х, без вариантов. Значит, надо арендовать маленький VPS, и сделать проброс через него.

Самый простой способ – туннель через ssh. На домашнем сервере (буду называть его iob.xxx.xx) выполняю:

ssh -N -T -R pub.xxx.xx:1883:127.0.0.1:1883 a@iob.xxx.xx 

Подключаясь к порту 1883 внешнего сервера pub.xxx.xx, в реальности оказываешься на домашнем iob:1883 c запущенным контейнером mqtt (mosquito).

Естественно, нужно, чтобы это стартовало автоматически, соединение восстанавливалось после сбоя. Поэтому воспользовался autossh, оформив как сервис.

/etc/systemd/system/ssh_mqtt.service:

[Unit] Description=SSH Tunnel mqtt After=network.target  [Service] Environment="AUTOSSH_GATETIME=0" ExecStart=autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -NR pub.xxx.xx:1883:127.0.0.1:1883 -i /home/a/.ssh/id_rsa a@pub.xxx.xx  [Install] WantedBy=multi-user.target

Всякие systemctl enable/restart и т.п. я уж не буду описывать.

К сожалению, несмотря на autossh, меня преследовали постоянные зависания. Так что я решил, что незачем плодить сущности и остановился на обычном ssh:

/etc/systemd/system/ssh_mqtt.service:

[Unit] Description=SSH Tunnel mqtt After=network.target  [Service] Restart=always RestartSec=20 User=anri ExecStart=/bin/ssh -N -T -R pub.xxx.xx:1883:127.0.0.1:1883 -i /home/a/.ssh/id_rsa a@pub.xxx.xx  [Install] WantedBy=multi-user.target

Впоследствии, кстати, оказалось, что это провайдер такой косой. Ну или самый дешевый тариф за 45 руб/мес так криво у него работает. Сессия периодически зависает, даже когда просто по ssh подключен (MobaXterm). Так что заказал я себе в итоге VPS у другого (55 руб/мес), и проблемы с зависаниями исчезли.

Кстати, выбирал я себе, где VPS взять не только исходя из цены, но и с учетом пинга (10-20ms).

В общем, такой вариант вполне норм, особенно с учетом того, что впоследствии я сделал подключение через Интернет исключительно на порт 8883 через TLS. Т.е. пароль для mosquitto передавался зашифрованным.

Впоследствии сделал обязательными и клиентские сертификаты. Т.е. сначала на уровне TLS надо предъявить клиентский сертификат, а потом уже авторизоваться именем-паролем, заданным в mosquito. Т.е. до фазы перебора паролей не так просто добраться.
Соответственно сначала использовал сертификат сервера от LetsEncrypt, потом, из-за необходимости клиентских сертификатов, перешел на самоподписание.

Поскольку в процессе я дорабатывал и ПО для ESP32, заметил (или просто подумал, уже не помню), что при проблемах с VPN подключением аккумулятор будет расходоваться существенно быстрее. При нормальной работе цикл: Проснуться, подать питание на датчики, подключиться к WiFi, установить соединение с сервером mqtt, считать показания датчиков, как будут готовы, передать на mqtt, отключить питание с датчиков, уйти в deep sleep минут на 10.

В норме такой цикл занимает примерно 4 секунды. 1.5-2 секунды — подключение к WiFi, дополнительная секунда из-за перехода на mqtt over TLS. 4 секунды устраивает, все равно датчикам нужно время, чтобы проснуться. А вот если VPN лег (это было хорошо заметно, когда autossh отваливался), что делать? Я, конечно, настроил, чтобы через 20 секунд все равно система засыпала. Но 20 секунд вместо 4 – это весьма ощутимо.

В общем, я решил, что mqtt сервер лучше держать на внешнем VPS. Сейчас, когда все работает, как часы, я не уверен, что это необходимо. Но и переделывать обратно смысла не вижу.

Публичный адрес для Vis

Vis – популярная система визуализации в ioBroker. Можно было не заморачиваться, и ее саму настроить на https и аналогично просто пробросить порт. Тем более, что пароль она может спрашивать на уровне приложения.

Но это не круто. Особенно с учетом того, что для работы она подключает дополнительные сервисы. Скажем, графики я рисую в flot, Условно говоря, подключаюсь я к vis.xxx.xx:8082/vis/index.html, а внутри есть ссылки на графики vis.xxx.xxx:8082/flot/index.html. В какой-то момент оказалось, что при подключении к /vis пароль спрашивается, а интерфейс графиков доступен без пароля.

В какие-то моменты вообще странно было – на vis авторизовался, график вижу, но справа внизу полупрозразчное окошко «No connection to server». Переписал для этого блока css, чтобы скрыть его. Но, как только стал использовать frame для переключения между графиками на одном экране, оказалось, что мое перекрытие на отображение во фрейме не действует. (Как потом выяснилось, так и должно быть). Отключаю авторизацию – все прекрасно, никаких ругательств.

Так что решил я на том самом внешнем сервере поднять nginx в режиме reverse proxy. И уже на нем сделать авторизацию.

Из браузера заработало. Но родное приложение iobroker.vis из Play Market так авторизоваться не смогло. А хотелось им пользоваться. Хоть это и фактически браузер в окошке, но есть у него ряд приятных фич. Скажем, задал масштаб (93% при вертикальном режиме), и изображение вписалось. На другом устройстве с другим разрешением экрана просто подбираешь коэффициент, и все. А в браузере надо каждый раз подстраиваться…

Ладно, думаю. Добавлю вместо пароля хитрый код в URL. Типа vis.xxx.xx:8082/<длинная последовательность>/vis/index.html. Часто такой трюк используется.

Почти заработало. Но с глюками, копание показало, что вот это веб приложение написано не совсем корректно. Многие ссылки внутри него не относительные, а от корня.

Ладно, несколько ссылок выявил, для них написал, мол, если referrer содержит такой код, все равно доверяй, перепиши URL и т.п. Но они постепенно еще выявлялись. Так что я решил, что это криво, неправильно, и нужен другой подход.

VPN

Решил я немного пожертвовать универсальностью доступа. Пусть у меня будет доступ с моего ноута, смартфона. Но с чужих устройств, из интернет-кафе не надо, обойдусь. Тогда можно поставить небольшого клиента, который будет устанавливать VPN. И внутри него не требуется ни SSL, ни авторизация. И при этом ссылки переделывать не надо.

Простейшим способом для меня оказался Zerotier. Для моих ОС (Windows, Android, Linux) клиенты есть. Причем есть даже готовые в докере. Да. Я все запускаю в докере, про особенности этого позже.

Устанавливаешь клиента, вводишь уникальный код своей сети, потом в Web-интерфейсе на my.zerotier.com его подтверждаешь, при необходимости задаешь статический адрес из личной приватной сети (а-ля 10.20.30.0), и все. Все подключенные клиенты видят друг друга.

Единственное, с чем пришлось поразбираться немного, это «как с устройства в домашнем WiFi подключиться к удаленному серверу, не запуская клиента». Ну у меня же сервер домашний уже является клиентом, пусть и маршрутизирует себе. Оказалось, все просто. Домашнюю сеть 192.168.х.0 надо на my.zerotier.com прописать в разделе Managed Routes, указав в качестве gateway, естественно, этот мой домашний сервачок. Ну и в WiFi сети настроить маршрут соответственно (на WiFi роутере статика 10.20.30.0 на домашний сервер).

Можно при подключении клиента Zerotier указывать другой DNS сервер. Т.е. подключил клиента, и доменное имя резолвится уже не в публичный адрес, а в приватный, поскольку DNS теперь указывает на домашний сервер, где dnsmasq подсовывает для отдельных записей IP из приватной сети Zerotier.

Еще Zerotier порадовал эффективным выбором маршрута для подключения. Если я в домашнем WiFi активирую клиента Zerotier, пинг до домашнего компьютера (его IP адреса, выданного Zerotier) те же пара милисекунд, что и без клиента (просто по WiFi). Т.е. подключение к облаку идет только в первый момент. Дальше обмен трафиком осуществляется напрямую, не через облако. Если установить, к примеру, OpenVPN на VPS, аналогичный трафик бежал от клиента на VPS, а потом обратно в ту же WiFi сеть к домашнему серверу.

В принципе есть даже фишка ставить свои moon серверы. Чуть ли не в отрезанной от Интернета сети все это хозяйство развернуть.

Что в итоге?

ESP32 шлет свои данные на mqtt сервер, развернутый на VPS. Over TLS, client certificate required.

С домашним сервером установлен VPN через Zerotier. Через этот домашний сервер с mqtt на VPS связывается Sonoff rfBridge с прошивкой Tasmota. Там нет возможности задать TLS с клиентским сертифкатом, потому настроен обычный MQTT на 1883. Все равно ведь домашний сервер этот трафик зашифрует с помощью Zerotier.

Ну и я подключаюсь к vis из домашней сети непосредственно, а из Интернета активировав клиента Zerotier. Можно его вообще не отключать, так тоже работает. Вот только иногда мне и другие VPN клиенты нужны (например, сходить на «РКН-запрещенку»). Два VPN на одном смартфоне сразу не сдружились, а разбираться я не стал.

Все очень просто. Но червячок душу глодал. Хоть у меня и не ядерный реактор, но вдруг? Был же случай, когда сломали TeamViewer (компанию, а не конкретно клиентское ПО), и через них получили доступ к многим аккаунтам. И вообще я писал в самом начале, что все свое люблю.
Так что следующим шагом я перешел с Zerotier на OpenVPN. Тут уж все в моих руках.

Единственное «чужое» — это VPS у провайдера. Ну так я специально все в докер контейнерах запускаю, чтобы иметь возможно моментально переехать.
Если б знал, сколько придется разбираться с OpenVPN, может и не стал бы. Справедливости ради – основные проблемы были именно из-за контейнеров.

Заключение

В следующей статье расскажу про OpenVPN и особенности настройки в моих условиях (контейнеры, маршрутизация других устройств из домашней сети). Там будет больше конфигов, технических деталей и сложностей. Но сразу вторую часть писать без этой не стал. Было бы не понятно, зачем вообще такие извращения.

И на всякий случай вопрос к знающим: хоть у меня VPS и маленький (512MB RAM), используется он меньше, чем на 1%. docker stats:

image

И появилась у меня мысль запустить это все именно как контейнер на каком-нибудь Google Cloud Run, Amazon Fargate или чем-то подобном. Развернуть сервер со всякими fail2ban через ansible – не проблема. Установить Docker тоже. Но зачем, если нужна только маленькая толика его ресурсов?

Однако, по моим расчетам тот же Fargate мне обошелся бы в разы дороже.

Может я чего-то не понял? Так-то было бы интересно иметь маленький контейнер чисто для проброса порта домой, а не целый VPS. Нет такого?

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

Дайджест свежих материалов из мира фронтенда за последнюю неделю №417 (25 — 31 мая 2020)

Предлагаем вашему вниманию подборку с ссылками на новые материалы из области фронтенда и около него.

Медиа    |    Веб-разработка    |    CSS    |    JavaScript    |    Браузеры    |    Занимательное    |    

Медиа

podcast Подкаст «Пятиминутка React»: ReasonML в 2020 году
podcast UnderJS Podcast #22 — GitLab, GraphQL, Vue3 c Наталией Теплухиной [Ламповый]
podcast Подкаст CSSSR «Argumentarium»: Svelte и «Большая тройка» JS-фреймворков
podcast video Pro Conf #64: ReactEurope 2020 — Замена Redux от Facebook | Быстрый Gatsby | React Native для веба | Next.js
video en Ссылки на все слайды и видео с ngVikings 2020
video en Jamstack conf virtual 2020

Веб-разработка

habr Почему Евросоюз искореняет cookie-стены
habr Как обезопасить свой веб-сайт?
Типографика для web
en Свежий номер журнала Increment, посвященный фронтенду. Актуальные статьи от звезд индустрии — Chris Coyer, Lea Verou, Evan You и других
en Руководство по синтаксису адаптивных изображений в HTML
en Самые большие скандалы с NPM
en Пример использования Wake Lock API: 300% увеличение показателей purchase intent на BettyCrocker.com
en htmx — мощные инструменты для HTML, позволяющие получать доступ к AJAX, WebSockets и Server Sent Events напрямую в HTML, используя атрибуты
en Отзывчивому веб-дизайну исполняется десять лет.
en #20 HTMHell special: close buttons. Паттерны и антипаттерны реализации кнопок закрытия
en Использование структурированных данных для улучшения поисковой оптимизации

CSS

en Вопрос эксперту: почему CSS такой… какой он есть?
en Руководство пользователя по переменным в CSS
en Tailblocks — готовые к использованию CSS блоки для Tailwind
en О фиксированных элементах и ​​фонах
en Первый взгляд на `aspect-ratio`
en Вот что я не знал о “content”
en Расширяющаяся гамма цветов в вебе
en Создание дополнительных градиентов с помощью фильтров CSS
en CLI-инструмент для создания CSS Grid layouts

JavaScript

habr Новшества ES2020, которые мне очень нравятся
habr О каждодневном совершенствовании JavaScript-программиста
habr Эффект реалистичного перелистывания страниц на JS
habr Что такое Deno и заменит ли он Node.js?
Взгляд на JavaScript со стороны
en 5 главных причин, почему Javascript разработчики предпочитают Deno, а не Node
en Базовый веб-скрапинг веб-страниц с использованием JavaScript с Node.js + Puppeteer
en ECMAScript 4: недостающая версия

Браузеры

en Как Microsoft делает Edge лучшим браузером для PWA
en Браузеры не являются движками рендеринга
en Chrome 84 Beta: Web OTP, Web Animations, New Origin Trials и многое другое
В Chrome 84 по умолчанию включат защиту от назойливых уведомлений

Занимательное

Microsoft развивает новый открытый пакетный менеджер winget
Устаревание корневого сертификата AddTrust привело к сбоям в системах с OpenSSL и GnuTLS
en Самый забагованный сайт в интернете (убедитесь сами, открыв консоль)
en Забавный факт: интерфейс для управления Dragon 2 работает на Chromium и JavaScript
en Stackoverflow Developer Survey 2020: результаты ежегодного опроса разработчиков

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

Дайджест за прошлую неделю.
Материал подготовили dersmoll и alekskorovin.

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

Подкаст «ITMO Research»: как подойти к синхронизации AR-контента с шоу в масштабе целого стадиона

Это первая часть текстовой расшифровки второго интервью для нашей передачи (Apple Podcasts, Яндекс.Музыка). Гость выпуска — Андрей Карсаков (kapc3d), к.т.н., старший научный сотрудник Национального центра когнитивных разработок, доцент Факультета цифровых трансформаций.

С 2012 года Андрей работает в научной группе Визуализация и компьютерная графика. Занимается крупными прикладными проектами на государственном и международном уровне. В этой части беседы мы говорим о его опыте AR-сопровождения массовых мероприятий.


Фото ThisisEngineering RAEng (Unsplash.com)


Контекст и задачи проекта

Таймкод (по аудиоверсии) — 00:41


dmitrykabanov: Я бы хотел начать с проекта «Европейские игры». Он многокомпонентный, в подготовке участвовало несколько команд, а обеспечить дополненную реальность для многотысячной аудитории прямо во время мероприятия на стадионе — достаточно серьёзная задача. С точки зрения вашего участия, это было программное обеспечение в первую очередь?

kapc3d: Да, мы сделали программную часть и обеспечивали сопровождение во время проведения шоу. Нужно было в реальном времени все отслеживать, мониторить и запускать, еще — работать с телевизионной группой. Если рассматривать этот проект в целом, то можно говорить про церемонии открытия-закрытия Европейских игр в Минске, а также про церемонию открытия чемпионата WorldSkills в Казани. Это была одинаковая схема работы, но разные мероприятия. Между ними был промежуток в два месяца. Проект мы готовили вместе с ребятами из компании Sechenov.com.

Познакомились с ними случайно на Science Fest, который проходил осенью 2018 года. Наши магистранты шоукейсились со своим курсовым проектом по теме VR. Ребята подошли к нам и спросили, чем мы занимаемся у себя в лаборатории. Выглядело это примерно так:

— Вот вы с VR работаете, а с дополненной реальностью умеете?

— Ну, вроде как, да.

— Есть такая задача, с такими вводными. Сможете сделать?

Репу немножко почесали, нереального вроде ничего нет:

— Давайте попробуем предварительно все изучить, а далее — найдем решение.

Дмитрий: Они занимаются только медийным сопровождением?

Андрей: Делают full stack. С точки зрения менеджмента и организации — полностью занимаются режиссурой, постановкой, подбором декораций, логистикой и прочим техническим обеспечением. Но им хотелось сделать что-то особенное для Европейских игр. Данные спецэффекты, вроде смешанной реальности, делают для телевидения достаточно давно, но они не самые бюджетные с точки зрения технической реализации. Поэтому ребята искали альтернативные варианты.

Дмитрий: Давайте подробнее обсудим задачу. В чём она состояла?

Андрей: Есть мероприятие. Оно длится час-полтора. Нужно сделать так, чтобы зрители, которые смотрят его в прямом эфире, и те, кто сидят на стадионе, могли увидеть эффекты с дополненной реальностью с полной синхронизацией с живым шоу по времени и расположению на площадке.

Был ряд технических ограничений. Нельзя было делать синхронизацию по времени через интернет, потому что были страхи по поводу избыточной нагрузки на сеть при полных трибунах и перспектива посещения мероприятия главами государств, из-за чего мобильные сети могли глушить.

Андрей Карсаков, фото из материала Университета ИТМО
У нас было два ключевых компонента этого проекта — персональный опыт, который люди могут получить через мобильные устройства, и то, что идёт в телевизионную трансляцию и информационные экраны на самом стадионе.

Если вдруг человек смотрит через мобильное устройство эпизоды дополненной реальности и одновременно попадает на экран, он должен увидеть ту же самую картинку.

Нам нужно было две фактически разные системы полностью синхронизировать по времени. Но особенность таких шоу в том, что это комплексные мероприятия, где задействовано большое количество технических служб и все операции выполняются по тайм-кодам. Тайм-код — это конкретный момент времени, в который что-то стартует: свет, звук, выход людей, открывающиеся лепестки сцены и так далее. Мы должны были подстроиться под эту систему, чтобы всё у нас запускалось в нужный момент. Еще одна особенность была в том, что сцены и эпизоды с дополненной реальностью были сценарно завязаны между собой.

Дмитрий: Но вы всё-таки решили отказаться от использования тайм-кодов, из-за высоких рисков возникновения форс-мажоров, либо изначально посчитали какие-то мощностные характеристики и поняли, что нагрузка на всю систему будет достаточно высокая?

Андрей: Если делать сервис синхронизации на такую аудиторию, то это не сильно сложно. Запросы в любом случае не будут валиться в один момент. Да, нагрузка высокая, но это не аврал. Вопрос в том, стоит ли тратить на это ресурсы и время, если неожиданно сеть погасят. Мы не были уверены, что этого не произойдет. В конечном счете всё работало, с перебоями из-за нагрузки, но работало, а мы — синхронизировались по тайм-коду по другой схеме. Это был один из глобальных челленджей.


Сложности реализации с точки зрения UX

Таймкод (по аудиоверсии) — 10:42


Андрей: Еще нам нужно было учитывать, что стадион — это не классическая концертная площадка, и синхронизировать системы по пространству для мобильных устройств. Так, какое-то время назад вирусилась история с дополненной реальностью на концертах Eminem, потом был кейс с Лободой.

Фото Robert Bye (Unsplash.com)
Но это — всегда экспириенс in front of you — вся толпа стоит перед сценой, синхронизация достаточно простая. В случае со стадионом нужно понимать, с какой ты стороны находишься по окружности, относительное положение, чтобы стадион сел в то пространство, которое в виртуальной среде есть. Это был некислый челлендж. Пытались решить его различными способами, и получился близкий кейс к тому, что было реализовано у Лободы, но не во всем.

Мы давали пользователю самому определиться, где он находится. Сделали разметку стадиона, где люди выбирали сектор, ряд, место. Все это — в четыре «клика». Далее нам оставалось определить направление на сцену. Для этого мы показывали силуэт того, как примерно должна выглядеть сцена с пользовательского ракурса. Он совмещал его, тапал и всё — сцена садилась. Мы старались максимально упростить этот процесс. Все-таки 90% зрителей, которые хотели посмотреть шоу, — это не те люди, которые имеют опыт общения с дополненной реальностью.

Дмитрий: Для этого проекта было отдельное приложение?

Андрей: Да, приложение для iOS и для Android, которое мы пушили в сторы. По нему была отдельная промо-кампания. Было предварительно подробно рассказано, как скачать и прочее.

Дмитрий: Надо понимать, что человеку негде физически проверить и поучиться использовать такое приложение. Поэтому задача с «обучением» аудитории усложнялась.

Андрей: Да-да. С UX мы наловили много шишек, потому что пользователь хочет опыт получить в три клика: скачал, установил, запустил — заработало. Многим лень ходить сложными туториалами, читать обучение и прочее. И мы не старались всё максимально объяснить пользователю в туториале: здесь откроется окошко, здесь доступ к камере, иначе не заработает и так далее. Сколько бы ты не писал объяснений, как бы ты подробно не разжевывал, какие бы гифочки не вставлял, народ этого не читает.

В Минске мы собрали большой пул фидбека по этой части, и уже многое изменили для приложения в Казани. Мы загоняли туда не только те фонограммы и те тайм-коды, которые соответствуют конкретному эпизоду дополненной реальности, а брали полностью все фонограммы и тайм-коды. Так приложение слышало, что происходит в момент запуска, и — если человек не в тот момент зашёл — выдавало информацию: «Товарищ, извини, твой AR-эпизод будет через 15 минут».


Немного об архитектуре и подходе к синхронизации

Таймкод (по аудиоверсии) — 16:37


Дмитрий: Синхронизацию всё-таки решили делать по звуку?

Андрей: Да, это получилось случайно. Мы перебирали варианты и натолкнулись на компанию Cifrasoft из Ижевска. Они делают не особо навороченную, но железно работающую SDK, которая позволяет по звуку синхронизироваться с таймингом. Систему позиционировали для работы с ТВ, когда ты по звуку условной рекламы можешь выводить что-то в приложении или по дорожке фильма давать интерактив.

Дмитрий: Но одно дело — ты сидишь у себя в гостиной, а другое — многотысячный стадион. Как у вас все сложилось с качеством записи звука и его последующим распознаванием?

Андрей: Было много страхов и сомнений, но в большинстве случаев всё распознавалось хорошо. Они строят сигнатуры по звуковой дорожке своими хитрыми алгоритмами — итог весит меньше исходного аудиофайла. Когда микрофон слушает окружающий звук, он пытается найти эти особенности и распознать трек по ним. В хороших условиях точность синхронизации 0,1-0,2  секунды. Этого было более чем достаточно. В плохих условиях расхождение было до 0,5 секунды.

Многое зависит от девайса. Мы работали с большим парком устройств. Для айфонов — это всего 10 моделей. Они работали нормально с точки зрения качества и прочих особенностей. Но с андроидами зоопарк такой, что мама моя. Не везде получалось так, что звуковая синхронизация срабатывала. Были кейсы, когда на разных устройствах, притом разные треки, не получалось услышать из-за каких-то особенностей. Где-то уходят низкие частоты, где-то — высокие начинают хрипеть. Но если в девайсе был нормализатор на микрофоне, синхронизация всегда срабатывала.

Дмитрий: Расскажите, пожалуйста, об архитектуре — что использовали в проекте?

Андрей: Приложение мы делали на Unity — самый простой вариант с точки зрения мультиплатформенности и работы с графикой. Использовали AR Foundation. Мы сразу сказали, что не хотели бы усложнять систему, поэтому ограничились парком устройств, которые поддерживают ARKit и ARCore, чтобы успеть все протестировать. Сделали плагин для цифрасофтовской SDK, он лежит у нас на GitHub. Сделали систему менеджмента контента, чтобы сценарии запускались по таймлайну.

Повозились немного с системой частиц, потому что пользователь может зайти в любое время конкретного эпизода, и нужно, чтобы он увидел все с того момента, с которого он засинхронизировался. Повозились с системой, которая позволяет сценарии воспроизводить чётко по времени, чтобы трехмерный опыт можно было, как в фильме, прокручивать вперёд-назад. Если с классическими анимациями это работает «из коробки», то с системами частиц пришлось повозиться. В какой-то момент они начинают спауниться, и если ты оказываешься где-то до точки спауна, они ещё не родились, хотя вроде должны быть. Но эта проблема, на самом деле, достаточно легко решается.

Для мобильной части архитектура достаточно простая. Для телетрансляции всё сложнее. У нас были ограничения по железу. От заказчика было поставлено условие: «Вот у нас есть такой-то парк железа, грубо говоря, надо, чтобы на нем всё работало». Мы сразу ориентировались на то, что будем работать с относительно бюджетными картами видеозахвата. Но бюджетные — это не значит, что плохие.

Было ограничение по железу, по картам видеозахвата и по условиям работы — как мы должны получать картинку. Карты захвата — Blackmagic Design, работали по схеме Internal keying — это когда к тебе заходит видеокадр с камеры. У карточки есть свой процессинговый чип, куда заводится ещё и кадр, который должен накладываться поверх входящего. Карточка их смешивает — больше мы там ничего не трогаем и не влияем на кадр с видеокамеры. Результат через видеовыход она выплёвывает на пультовую. Это хороший метод для накладывания титров и прочих подобных вещей, но он не очень подходит для эффектов смешанной реальности, потому что там много ограничений на render pipeline.

Дмитрий: С точки зрения вычислений в реальном времени, привязки объектов или чего-то еще?

Андрей: С точки зрения качества и достижения нужных эффектов. Из-за того, что мы не знаем, поверх чего накладываем картинку. Мы просто отдаем информацию о цвете и прозрачности поверх исходного потока. Некоторых эффектов вроде преломлений, корректной прозрачности, дополнительных теней при такой схеме невозможно добиться. Для этого нужно все рендерить вместе. Например, никак не получится сделать эффект искажения воздуха от костра или от горячего асфальта. То же самое с передачей эффекта прозрачности с учетом показателя преломления. Мы изначально делали контент, исходя из этих ограничений, и старались использовать соответствующие эффекты.

Дмитрий: У вас был свой контент уже на первом проекте для Европейских игр?

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

Если говорить про пайплайн, то для телевещания мы всё собирали на Unreal Engine 4. Так совпало, что они как раз в тот момент начали форсить свой инструментарий для смешанной реальности (mixed reality). Оказалось, что всё не так просто. Весь инструментарий даже сейчас сырой, нам много пришлось вручную допиливать. В Минске мы работали на кастомной сборке движка, то есть мы некоторые вещи внутри движка переписывали, чтобы, например, можно было тени рисовать поверх реальных объектов. На той версии движка, которая была тогда актуальна, не было фич, позволяющих это делать с помощью стандартного инструментария. По этой причине у нас ребята делали свою кастомную сборку, чтобы обеспечить все, что было жизненно необходимо.


Другие нюнасы и адаптация к WorldSkills в Казани

Таймкод (по аудиоверсии) — 31:37


Дмитрий: Но всё это в достаточно сжатые сроки?

Андрей: Сжатые сроки были по казанскому проекту, по минскому — нормальные. Где-то полгода на разработку, но с учётом того, что было задействовано шесть человек. Параллельно делали мобильную часть, разрабатывали инструментарий для телепродакшена. Там был не только вывод картинки. Например, система трекинга с оптикой, для этого нужно было свой инструментарий делать.

Дмитрий: Была адаптация от одного проекта к другому? За полтора месяца нужно было воспользоваться наработками и переложить проект с новым контентом на новую площадку?

Андрей: Да, это было за полтора месяца. У нас был запланирован двухнедельный отпуск всей команды после минского проекта. Но сразу после закрытия ребята из Sechenov.com подходят и говорят: «Ну что, давайте тогда Казань делать». Хотя мы все-таки успели немного отдохнуть, переключились на этот проект достаточно быстро. Кое-что доделали по технической части. Большая часть времени была потрачена на разработку контента, потому что для WorldSkills его полностью мы делали, просто согласовывали с режиссёрской командой. С их стороны был только сценарий. Но было легче — не нужно было делать лишних итераций. Когда ты делаешь контент сам, сразу видишь, как это в движке работает, можешь быстро править и согласовывать.

По мобильной части учли все тонкости, которые у нас были по Минску. Сделали новый дизайн приложения, переработали немного архитектуру, добавили туториалов, но максимально коротко и наглядно постарались сделать. Сократили количество шагов пользователя от запуска приложения до просмотра контента. Полтора месяца хватило, чтобы сделать адекватный проект. За полторы недели вышли на площадку. Там работать было проще, потому что весь контроль над проектом был в руках организаторов, не нужно было согласовывать с другими комитетами. В Казани было проще и легче работать и вполне нормально, что времени было меньше.

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

Андрей: Да, мы оставили по звуку. Работало хорошо. Как говорится, если работает, не трогай. Мы просто учли нюансы по качеству звуковой дорожки. Когда делали вступление, как раз был тренировочный эпизод, чтобы люди могли попробовать до того, как шоу начнётся. Было удивительно, что когда в момент воспроизведения трека на стадионе идут бурные аплодисменты, «живые», система позволяет хорошо синхронизироваться по этому треку, но если в этот момент вместе с треком примешиваются записанные аплодисменты, то трек перестаёт ловиться. Вот подобные нюансы учли, и по звуку всё достаточно хорошо синхронизировалось.

P.S. Во второй части выпуска мы говорим о научной визуализации данных, моделировании процессов в других проектах, геймдеве и магистерской программе «Технология разработки компьютерных игр».

ссылка на оригинал статьи https://habr.com/ru/company/spbifmo/blog/504678/