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

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

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

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

Начало

Мой проект называется VRack (Virtual Rack), читается как "ВиРэк". Это инструмент, который упрощает написание сервисов для целей мониторинга, промышленной автоматизации, личной автоматизации или автоматизации бизнес процессов.

VRack - это self-hosted сервис, написанный на JavaScript (nodejs), основная задача которого - запускать в отдельных потоках сервисы, определенные пользователем.

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

Максимально упрощенная схема VRack:

  • External applications - Это внешние приложения, которые могу взаимодействовать с VRack с помощью WebSocket Data Provider.

  • API Master - Регистрирует команды других модулей для доступа к ним из External applications

  • Service Manager отвечает за запуск и контроль сервис-потоков, которые выполняют полезную работу.

При создании основного сервиса я старался придерживаться следующих требований:

  • Запуск везде, где только можно:

    • Минимальный по сложности деплой

    • Минимальное количество зависимостей

    • Минимальное требование к бекапу

  • Сервис должен жить максимально долго, без всяких sigfault

  • Сервис должен обеспечивать менеджмент других сервисов в отдельных потоках:

    • Запуск нового потока

    • Перезапуск при аварийном завершении

    • Получение и хранение ошибок при завершении потока

  • Сервис должен предоставить API для работы с сервис-потоками

  • Сервис должен быть легко расширяем. Он должен предоставлять все возможное для реализации конечного результата. Не нужен API сервер? отключаем. Не нравится WebScoket? заменяем. Нужен другой механизм авторизации? без проблем. Если у нас есть какие то особые требования, они должны легко удовлетворяться.

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

Пока разберем только основу - Service Manager

Сервис-потоки

Сервис-потоки - это сервисы, определнные пользователем, которые запускает Service Manager каждый в отдельном потоке.

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

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

Чтобы организовать сервис-поток, необходимо описать какие виртуальные устройства должны в нем запускаться и указать связи. Это делается с помощью схемы, которая представляет собой JSON файл, например:

{
   "devices": [
      {
         "id": "Interval1",         // Уникальный идентификатор устройства
         "type": "basic.Interval",  // Класс устройства
         "params": {                // Параметры устройства
            "timeout": 1000,
            "start": true
         }
      },
      {
         "id": "Debug",
         "type": "basic.Debug",
         "params": {}
      }
   ],
   "connections": [
      /**
      Указания связи описывается как:
      ИсходящееУстройство.исходящийпорт -> ВходящееУстройство.входящийпорт
      */
      "Interval1.gate -> Debug.debug1" 
   ]
}

Результат выглядит так:

Для сервис-потоков были определены следующие требования:

  • Никакого "программирования мышкой" - Это не очередной визуальный язык программирования, low-code платформа или тп, все придерживается абсолютно других концепций и правил

  • Структура сервис-потока не может меняться без перезагрузки (то есть добавление новых устройств в уже работающий сервис-поток невозможен)

  • Безопасное API - Для изменения схемы сервис-потока должен быть доступ к файловой системе сервера, либо какой-то механизм, определенный разработчиком. В таком случае, даже если сторонний человек получил доступ к интерфейсу управления, он не смог поменять структуру сервис-потока или увидеть параметры устройств (которые могут содержать пароли, токены и тп).

  • Модульность и расширяемость - Функционал сервис-потоков должны расширяться так же просто и эффективно, как и функционал основного сервиса

  • Генерация схемы сервис-потока - Как показала практика, генерация схемы сервис-потока позволяет решать сразу несколько проблем:

    • Наследование схем, очень помогает в решениях однотипных задач

    • Генерация схемы на основе конфигурационного файла

    • Лучше сгенерировать достаточно большую схему, чем набрасывать ее руками

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

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

Виртуальные устройства

Виртуальные устройства - Это классы, определенные пользователем и выполняющие необходимую работу. Пользователь сам пишет их (или берет готовые) и потом использует внутри сервис-потоков.

Возникает закономерный вопрос, а зачем писать какие то там виртуальные устройства, когда можно просто писать код библиотеки и вызывать его? Подход через реализацию виртуальных устройств позволяет создавать интуитивные абстракции. Схема сервис-потока предоставляет понятную документацию и структуру конечного сервиса. Такой подход отличается концептуально от написания классического линейно/асинхронного кода. У нас нет более точки входа в приложение типа index.js, потому что каждое виртуальное устройство это и есть точка входа в приложение. Такое решение очень хорошо вписывается в работу nodejs, упрощает декомпозицию кода и контроль.

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

Индикация

Виртуальное устройство может иметь обновляемую область памяти (Shares), которую можно получить с помощью API Master. Фактически это просто объект, который изменяет само устройство и после может оповестить через систему бродкастов всех заинтересованных. Таким образом, внешнее приложение может в онлайн режиме наблюдать изменения, которые происходят внутри виртуального устройства.

Органы управления

Органы управления в виртуальных устройствах VRack называются Action и представляют из себя специальные методы класса устройства, которые можно вызвать с помощью API Master. Все общение с устройствами происходит прозрачно, несмотря на то, что запрашиваются они у API Master основного процесса.

Порты

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

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

Сервисные сообщения

У виртуальных устройств есть возможность отправлять специальные сервисные сообщения о разных событиях внутри устройства. Такие сообщения также отправляются через систему бродкастов, то есть их можно получать в онлайн режиме. Сервисные сообщения могут содержать в себе объект с произвольными данными, которые поддерживает JSON (необходимо для сериализации/десериализации).

В отличие от других типов сообщений, тип action формируется автоматически, когда в устройство приходят Action запросы. Таким образом, разные пользователи VRack могут следить за тем, что каждый из них делает с устройствами в режиме онлайн.

Общие принципы работы

Выше были описаны основные компоненты работы VRack. Пришло время рассказать, как это работает.

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

Для начала, нам нужно определить, какие нам нужны порты для этого устройства. Мое предложение сделать один вход для подсчета и один выход для отправки в него результата подсчета. Назовем их increment и sum. Сюда же я бы добавил возможность сброса счетчика, добавив порт reset.

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

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

Напишем устройство Counter.js:

const { Device, Port } = require('vrack-core')

module.exports = class extends Device {
  description = 'Ведет подсчет входящих сигналов'
  /** Определение портов устройства */
  ports () {
    return [
      new Port('reset').input().data('signal').description('Сброс счетчика'),
      new Port('increment').input().data('signal').description('Добавление счетчика'),
      new Port('sum').output().data('number').description('Текущее значение счетчика')
    ]
  }

  /** Обновляемая область памяти */
  shares = { counter: 0 };

  /**
   * Для каждого входящего порта необходимо создать метод вызова
   * Он именуется как inputPort и вызывается автоматически
  */
  inputReset () {
    this.event('Reset counter', this.shares) // Отправка сообщения типа `Event`
    this.shares.counter = 0
    this.render() // Ставим устройство в очередь на отправку данных this.shares подписчикам
  }

  // Инкремент счетчкиа
  inputIncrement () { this.shares.counter++; this.render() }
}

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

Устройство Interval.js:

const { Device, Port, Rule } = require('vrack-core')

module.exports = class extends Device {
  description = 'Формирует сигнал через заданное время'
  ports () {
    return [
      new Port('gate').output().data('signal').description('Сигнальный выход')
    ]
  }

  /**
   * Описание параметров, которые мы ждем из файла сервис процесса
   * */
  checkParams () {
    return [
      new Rule('timeout').required().default(1000).isInteger().expression('value > 0')
        .description('Интервал в ms')
    ]
  }

  /**
   * Данный метод запускается автоматически после инициализации всех устройств
  */
  process () {
    /** Отправляем сигнал через заданое время */
    setInterval(() => { this.outputs.gate.push(1) }, this.params.timeout)
  }
}

Напишем файл сервис потока:

{
    "devices": [
        {
            "id": "Interval1",
            "type": "guide.Interval",
            "params": {
                "timeout": 1000
            }
        },
        {
            "id": "Interval2",
            "type": "guide.Interval",
            "params": {
                "timeout": 10000
            }
        },
        {
            "id": "Counter",
            "type": "guide.Counter",
            "params": {}
        }
    ],
    "connections": [
        "Interval1.gate -> Counter.increment",
        "Interval2.gate -> Counter.reset" 
    ]
}

В итогде наша схема будет выглядеть так:

Можно посмотреть в онлайн режиме как будет работать наша схема, подписавшись на канал shares данных (render) устройства Counter:

Если же подписаться на канал Event устройства Counter, то будем получать сообщения о сбросе счетчика:

Для устройств автоматически формируется документация, например, для Counter:

Hidden text

Counter

Ведет подсчет входящих сигналов

Входы:

  • reset signal - Сброс счетчика

  • increment signal - Добавление счетчика

Выходы:

  • sum number - Текущее значение счетчика

Параметры

Нет информации по параметрам

Пример конфигурации

{
   "id": "Counter",
   "type": "guide.Counter",
   "params": {}
}

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

Реальные примеры использования

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

Опрос котельной жилого дома

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

Вот сама схема (довольно большая):

Hidden text

Первая блок схема (1)

Схема опроса реальных устройств. Тут участвуют сразу 2 схемы опроса реальных устройств:

  • Первая схема используется для опроса 3х устройств (DEV::19, 27, 30), которые работают по очереди используя преобразователь интерфейсов типа Ethernet-RS485. Когда Provider подключается к реальному преобразователю, он передает специальный класс соединения через селектор следующему устройству, когда устройство заканчивает работу с соединением, оно информирует провайдер через микшер о том, что управление было передано ему обратно и цикл повторяется

  • Вторая схема более простая, устройство Dev::20 работает через Ethernet напрямую и не требует особой схемы для опроса

Все устройства опроса подключены в микшеры, которые преобразуют данные на входе в специальный тип данных метрик, имеющие формат типа

[timestamp, number, 'metricid']

У провайдера (Provider::21) есть несколько выходов для получения дополнительных метрик опроса. Это очень полезные метрики и позволяют получить, к примеру, среднее время задержки опроса реальных устройств и, тем самым, решить периодически возникающие проблемы. Эти параметры также заведены в отдельный микшер метрик.

Вторая блок схема (2)

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

Третья блок схема (3)

Отправка метрик в разные базы данных или разные таблицы. Мы храним данные метрик в Graphite для отображения в Grafana и эти же данные мы складываем в сыром виде для хранения в Clickhouse, так же в отдельную таблицу складываются служебные метрики сервис-потока (работа провайдера, занимаемая память).

Укладка данных в базы происходит через устройство Buffer, которое копит в себе метрики, пока их кто-то не заберет. ClickhouseInserter проверяет соединение с базой данных, делает тестовый запрос, и, если все в порядке, отправляет в порт Buffer.slice количество, которое он хочет получить из буфера (обычно 500). Буфер же отправляет в порт entities метрики в количестве <= 500. После того как ClickhouseInserter отправил все метрики в базу, отправляет количество вставленых метрик в порт shift, что приводит к смещению и удалению данных в Buffer.

Это очень полезная схема, которая позволяет терять связь с базой данных. После того, как связь возобновится, данные из буфера попадут в базу в полном объеме.

Устройство timeseries.List используется для переименования названия метрик (маппинг названий), это делается для разных баз по разному (происходит на этапе формирования схемы сервис-потока)

Четвертая блок схема (4)

Формирует данные о потреблении памяти внутри данного сервис потока. Мы собираем эти данные для контроля утечки памяти. И, хотя в случае правильного использования устройств и написания кода утечек не бывает, по таким параметрам можно определить утечки не совсем очевидных мест. Таким образом были найдены ошибки утечек в самом VRack на масштабе аптайма где-то 6 месяцев.

Пятая блок схема (5)

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

С помощью system.Transmitter можно передавать данные в порты устройств других сервис-потоков.

Заключение к данной схеме

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

Мелкие вспомогательные сервисы

VRack очень хорошо подходит для разнообразных маленьких сервисов. Поскольку VRack сам заботится о запуске/перезапуске сервис-потоков, вам необходимо сосредоточиться на написании только самого сервиса.

Ниже приведен пример небольшого сервиса:

Hidden text

В его задачи входит отслеживание SNMP Трапов коммутаторов локальной сети и отправка информации о них в телеграм. Если посмотреть внимательно на схему, то часть ее мы уже видели, а конкретно часть с отслеживанием сообщений внутри сервис-потока. К этой схеме был дописан TrapReceiver и вспомогательные устройства TrapManager и TrapAlert, которые в конечном итоге формируют сервисное сообщение типа alert, которые и отправляется к нам в телеграм.

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

Автоматизация с управлением

До этого были приведены примеры мониторинга и сбора данных. Справедливо будет привести пример автоматизации с управлением реальными устройствами.

Схема управления автоматизации шлагбаумами въезда/выезда КПП:

Hidden text

Первая блок схема (1)

Принимает информацию о фиксации камерой наблюдения подъезда автомобиля. Там приходят такие данные, как: номер, направление, камера, и тп. В зависимости от направления и принадлежности камеры, они распределяются на соответствующие выходы ReceiverAdapter.

Вторая блок схема (2)

Кажде 15 минут из внешнего приложения приходит новый список разрешенных автомобильных номеров, используя HTTP запрос. Проверить наличие номера в списке можно через входы Manager.number1... Эти входы работают в modeReturn и возвращают результат выполнения метода push, таким образом контроллеры узнают разрешения для номера авто.

Третья блок схема (3)

Состоит из 3х однотипных блоков управления шлагбаумами. Gateway собирает информацию о шлагбауме и передает ее в Controller. Когда в Controller приходит информация о подъехавшем автомобиле, он анализирует состояние шлагбаума и проверяет, можно ли его открыть. Если все соответствует нужным условиям, контроллер отправлять нужные сигналы на его открытие.

Четвертая блок схема (4)

Отправка в базу данных Clickhouse информацию о проезде автомобиля.

Пятая блок схема (5)

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

Заключение к данной схеме

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

Интерфейсы

Как только я познакомился с Vue2, тут же начал писать интерфейс для управление VRack. На данный момент этот интерфейс находится в достаточно плачевном состоянии, но может выполнять практически все основные функции.

Выглядит он примерное так:

Hidden text

Сверху расположено меню серверов, слева выбор дополнительного функционала и выбор сервиса, справа управление выбранным функционалом/сервисом.

После выбора включенного сервиса доступны 3 вкладки:

  • Управление - Основная информация/метаданные и кнопки управление (логическая проверка, запуск, перезапуск, остановка, удаление ошибок падений)

  • Устройства - Работа с устройствами, мониторинг, отслеживание соединений, вызов методов устройства

  • Схема - Карта устройств и их подключения

Во вкладе устройства можно подписываться на каналы и отслеживать сообщения устройства. В современной версии устройства в настройках передают список каналов, которые они используют, поэтому в интерфейсе отображаются только они (в данном случае устройство CU2 отправляет сообщения только в канал error).

Hidden text

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

Hidden text

Для каналов shares есть дополнительная вкладка Данные, в которой можно в онлайне наблюдать за обновлениями специальной области памяти устройства.

Hidden text

Для вызова методов устройства можно открыть через кнопку play специальное окно запроса. Функционал минимальный, заполнить ручками action c набором параметров и выполнить. Потенциально, тут заложено гораздо больше, можно было бы сделать выпадающее меню с выбором доступного метода, но, к сожалению, даже на красивый разбор ответа руки не дошли.

Hidden text

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

Hidden text

Свои интерфейсы

С появлением реактивных фреймворков типа Vue2/3 писать веб приложения для отображения данных в онлайн режиме стало действительно просто. Я предпочитаю делать небольшие веб интерфейсы для мобильных телефонов, но есть и приложения, написанные с использованием Electron или просто для настольных ПК.

Само по себе приложение обычно представлят из себя SPA приложение, которое отдается через очень простой сервер статики. Приложение имеет страницу настроек, которая сохраняет данные в localstorage браузера.

Выглядит как-то так:

Hidden text

После перехода на главную, происходит подключение к VRack и формируется интерфейс на основе структуры сервис-потока.

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

Несмотря на то, что Vector-AP занимается разработкой собственного сервера парковок со своим веб интерфейсом - Наш сервис в VRack значительно расширяет возможности и упрощает обслуживание парковки. Например, VRack формирует автоматически алерты по кассетам наличных денег, оповещая о том, что деньги заканчиваются и пора подкинуть еще наличных. Если физически открывается дверь паркомата - автоматически приходит фото в телеграм с камеры наблюдения. В интерфейсе можно выполнить специальные команды терминалов (паркоматы/стойки въезда/выезда).

Вот пример отображения стойки въезда:

Hidden text

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

Что еще?

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

На данный момент есть какая-никакая официальная документация, которую я старался поддерживать в актуальном состоянии - GitLab VRack, там же можно найти документацию на API и ссылки на остальные значимые проекты, связанные с VRack.

Есть демонстрация работы VRack в онлайне. Отображает состояние некоторых железок. Также на ней можно понажимать на виртуальные кнопки, которые управляют реальными устройствами. Очень большая просьба не взламывать ее.

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

Положительные особенности

Хотелось бы сказать про положительные особенности VRack, которые я могу сам отметить не как разработчик VRack, а как пользователь.

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

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

Еще огромным плюсом можно выделить вполне понятный деплой. В 90% случаев, чтобы перенести сервисы с одного сервера на другой, нужно просто скопировать одну папку и выполнить одну команду.

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

Классы устройств, например, добавляются не через npm в node_modules. Каждый набор устройств лежит в собственной папке с собственным package.json и собственной папкой node_modules. Такой подход позволяет использовать разные версии библиотек для разных наборов устройств.

В VRack уже решено много не очевидных проблем, например, вы можете держать в git схемы сервис-потоков. Но в сервис-потоках обычно могут храниться пароли или api-key. Для того, чтобы не хранить в git конфиденциальную информацию, вы можете подменять нужные вам параметры специальным файлом, который дублирует структуру сервис-потока, но подменят им только то, что там указано. Такие файлы обычно создаются отдельно и игнорируются в .gitignore.

Что дальше

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

VRack и все, что было для него сделано - сделал я один. Очень много времени было потрачено на тестирование концепций, переписывание и доработку библиотеки устройств и тп. А, поскольку разрабатываю я на нем один, у меня совсем нет мотивации доработать все до представительного вида.

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

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

Комментарии (9)


  1. fransua
    18.05.2023 15:30

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


    1. ponikrf Автор
      18.05.2023 15:30

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


      1. fransua
        18.05.2023 15:30

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


  1. serginho
    18.05.2023 15:30

    Интересно, каким образом зарабатываете на проекте. Доработка под заказ? Поддержка?


    1. ponikrf Автор
      18.05.2023 15:30
      +1

      Разработка, доработка и поддержка. Доработка в основном если меняется или добавляется оборудование. Чаще всего нужно только написать новое устройство (если нет готового) и подменить его в схеме - стоит это дешево.


  1. nin-jin
    18.05.2023 15:30

    Зачем JSON, если в формате Tree всё куда наглядней?

    device Interval1
    	type guide.Interval
    	param timeout 1000
    device Interval2
    	type guide.Interval
    	param timeout 10000
    	param retryCount 3
    device Counter
    	type guide.Counter
    connection
    	Interval1.gate -> Counter.increment
    	Interval2.gate -> Counter.reset
    

    Или даже так:

    Interval1 guide.Interval
    	timeout 1000
    Interval2 guide.Interval
    	timeout 10000
    	retryCount 3
    Counter guide.Counter
    	increment <= Internal1.gate
    	reset <= Internal2.gate
    


    1. ponikrf Автор
      18.05.2023 15:30

      Это не имеет значения. JSON конечно используется как формат для схемы, но он в 99% случаев формируется генератором.

      На самом деле можно написать адаптер, который будет из дерева формировать JSON, скорее всего модуль будет занимать не более 50 строк. Другое дело, готовы ли вы отказываться от генерации в пользу более понятного вида?


      1. nin-jin
        18.05.2023 15:30

        Зачем отказываться? Tree прекрасно генерируется.


  1. ilshatkin
    18.05.2023 15:30

    Привет коллега! У меня очень похожая ситуация с проектом.

    Круто и думаю что некое массовое использование и признание программе обеспечено.

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

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

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