Здравствуйте, друзья!

Сегодня я хочу рассказать вам, как открыл для себя новый язык программирования, среду исполнения, а ещё готовый фронт-энд. И всё это без кучи фреймворков и тысяч библиотек, чистое, непаханое поле…

Однако, давайте по порядку.

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

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

А фронтом стал Телеграм с его bot API. Тут можно создать приятный интерфейс и сделать взаимодействие с ботом, очень похожим на работу с обычной программой. Телеграм мультиплатформенный и с отличным бэк-эндом. Ему бы побольше элементов управления в API и цены б ему не было. Хотя, я уверен он будет развиваться.

Начать стоит с Микротика. Точнее, давайте рассмотрим его скриптовый язык. Он совсем не сложный и на первый взгляд не годится для серьёзной разработки. Но если копнуть глубже, то он раскрывается, хоть и содержит ряд ограничений.

Из самых досадных то, что из числовых имеем только целочисленный тип данных num. Пять разделим на два, получим два. В остальном вполне можно есть.

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

Рассмотрим наглядно. Обычный одномерный массив – это индексированный список. Элементы можно вставлять в любое место списка.

Одномерный ассоциативный, где элемент key=value, это тоже список, но сортированный по key.

Двумерный – это HashMap. Он же, но ассоциативный – сортированный map.

Из многомерного можно сделать сортированное дерево. Не сортированное тоже можно.

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

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

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

Кому нужны пруфы, прошу под кат.

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

:global queryID []
:global answerText []
:global answer ({
				"warning"=":global queryID; :global answerText; :log warning \"fQueryID=\$queryID fAnswerText=\$answerText\"; :delay 3; :log warning \"after delay\"";
        })

А тут мы инициализируем переменные, получаем код из массива и запускаем его на выполнение.

:global queryID 345554
:global answerText "Hello"
:global answer

:local exeText ($answer->"warning")

[[:parse $exeText]]
:log info "$exeText"

Чтобы передать параметры, нужно чтобы переменные были глобальными.

В данном случае код запускается командой :parse. Это значит, что сначала выполнится код из массива, а затем то, что идет после него (:log info "$exeText")

Команда :execute работает по-другому. Она запускает выполнение кода в отдельном потоке.

Да, многопоточность тоже доступна. Зависит от того, как вызывать код. Есть несколько способов. Из скрипта можем вызвать функцию, развернутую в глобальной переменной, выполнить код из :parse, или вызвать другой скрипт. В этом случае код, который идет ниже места вызова, будет ждать пока отработает его товарищ и только потом продолжит выполняться, если первый чего-нибудь не выкинет.

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

Под катом подробнее.

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

:global queryID []
:global answerText []
:global answer ({
				"warning"=":log warning \"fQueryID=\$queryID fAnswerText=\$answerText\"; :delay 3; :log warning \"after delay\"";
        })
:global queryID 345554
:global answerText "Hello"
:global answer

:local exeText ($answer->"warning")

:execute script=$exeText file=123.txt
:log info "$exeText"

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

Обратите внимание на отсутствие объявления глобальных переменных в коде из массива. В случае с :execute объявлять их там не надо.

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

Благодаря стараниям уважаемого автора Хабра, Александра @Chupakabra303, Микротик теперь понимает JSON. Автор создал набор библиотек, который парсит JSON объекты в многомерный ассоциативный массив и с ним уже можно работать всеми доступными методами.

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

Есть проверка синтаксиса. Можно вывести в консоль содержимое скрипта командой [/system script print from=script] и в месте, где есть ошибка шрифт станет монохромным. Если ошибок нет, то будет разноцветным, как новогодняя ёлка.

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

Ах, да. Нужна нормальная среда разработки. Таких много. Для себя выбрал редактор Atom от команды GitHub. У него есть много плагинов, в том числе RouterOS plugin. Плюс нативная поддержка контроля версий Git. Работать вполне комфортно.

Всё это в совокупности позволяет создать на базе RouterOS полноценный бэк-энд для мобильных приложений. Для Телеграм вообще подходит идеально.

Многие правильно подметят, а как же базы данных? Где данные хранить, запросы куда отправлять?

Это тоже решаемо. Есть СУБД как SQL, так и noSQL, которые поддерживают HTTP(S) API и JSON. Для управления временными рядами есть InfluxData, которая из коробки работает с https и JSON. Она подходит для мониторинга параметров самого устройства, а также для сбора всевозможных метрик с фронта. Дружит с Grafana, есть дашборды и всё красиво.

А можно использовать массивы. И даже создать СУБД на их основе, с запросами и прочим. Когда будет время займусь этим плотнее.

И все это не только для управления параметрами маршрутизатора. Ничего не мешает обрабатывать данные других сервисов с JSON сериализацией и возвращать результат. Если развернуть RouterOS в виртуальной среде, то можно оперировать ресурсами. Захостить её в облаке не проблема.

Пока это только теория. А как на практике? Покажу на примере Телеграм бота, который разработан с использованием почти всех, описанных выше, возможностей. Здесь кода не будет. Скорее демонстрация работы связки Микротик плюс Телеграм. Архитектура приложения, интерфейс, bot API и немного о безопасности.

Так выглядит главное окно бота.

Начнем с архитектуры. Мне понравилась статья одного из авторов Хабра "Создание архитектуры программы или как проектировать табуретку".

Приведу небольшую выдержку из нее.

Начнем с архитектуры. Мне понравилась статья одного из авторов Хабра "Создание архитектуры программы или как проектировать табуретку".

Приведу небольшую выдержку из нее.

Не смотря на разнообразие критериев, все же главной при разработке больших систем считается задача снижения сложности. А для снижения сложности ничего, кроме деления на части, пока не придумано. Иногда это называют принципом «разделяй и властвуй» (divide et impera), но по сути речь идет об иерархической декомпозиции. Сложная система должна строится из небольшого количества более простых подсистем, каждая из которых, в свою очередь, строится из частей меньшего размера, и т.д., до тех пор, пока самые небольшие части не будут достаточно просты для непосредственного понимания и создания.

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

Библиотечные. Часто используются другими модулями и реализуют работу с API Телеграм например. Отвечают за отправку сообщений или построение кнопок и клавиатур.

Функции создания пользовательских интерфейсов. Они "рисуют окна" исходя из назначения и переданных параметров.

Функции обработчики. Эти содержат логику и обрабатывают команды, полученные от клиента. Для каждого модуля свой обработчик.

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

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

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

Конечно все паттерны тут не реализуешь, но...

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

Масштабируемость (Scalability) - возможность расширять систему и увеличивать ее производительность, за счет добавления новых модулей.

Ремонтопригодность (Maintainability) - изменение одного модуля не требует изменения других модулей

Заменимость модулей (Swappability) - модуль легко заменить на другой

Возможность тестирования (Unit Testing) - модуль можно отсоединить от всех остальных и протестировать / починить

Переиспользование (Reusability) - модуль может быть переиспользован в других программах и другом окружении

Сопровождаемость (Maintenance) разбитую на модули программу легче понимать и сопровождать

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

Чтобы не дублировать код в модулях, были написаны библиотечные функции для работы с bot API. Их я выложил на русскоязычном форуме Микротик, кому надо можете пользоваться. Там есть всё, чтобы создать и отправить сообщение с текстом, фото, клавиатурой и т.д. Для редактирования и удаления тоже есть.

Настройки самого бота хранятся в массиве и считываются оттуда по необходимости.

Безопасность обеспечивается управлением пользовательскими разрешениями. Они тоже хранятся в массиве. Проверяются в функции обработчике перед выполнением команды.

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

Резюмируя можно сказать, что RouterOS, на мой взгляд, является неплохой средой разработки и исполнения. Конечно со своими тараканами, но их не так много. Я уверен, что рано или поздно её "распробуют" и другие разработчики приложений.

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

Конечно много чего ещё хочется написать, но тогда статья слишком распухнет. И так занял много вашего времени.

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

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


  1. MentalBlood
    04.09.2022 11:21
    +2

    Я писал на Си, на Ява и там много различных структур данных: деревья, списки, мапы. Тут в явном виде ничего этого нет

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


    1. ASD2003ru
      04.09.2022 13:37
      +2

      Если я не ошибаюсь то в микроте и есть LUA. Может немного подпиленный.


    1. staticmain
      05.09.2022 00:25
      +3

      Я писал на Си, на Ява и там много различных структур данных: деревья, списки, мапы. Тут в явном виде ничего этого нет

      Простите, но на си в явном виде тоже ничего такого нет. В Си указатели, из которых сам программист уже собирает то, что ему надо - хоть массив, хоть граф, хоть N-мерное SB-дерево


      1. BrookXVII Автор
        05.09.2022 01:48

        Да, простите за неточность. Поправлю в тексте, чтобы не было разночтений.


  1. BrookXVII Автор
    04.09.2022 17:01
    +2

    Полностью согласен, это LUA. Только имеет свою родную среду исполнения и немного доработан.


  1. Chupaka
    04.09.2022 22:47

    :parse для функций?.. 9 лет назад добавили как будто более адекватный синтаксис, почему бы про него не рассказать?

    :global getSum do={\
      if ($debug = 1) do={:put "Summing $1 and $2"};\
      :return ($1 + $2)\
    }
    
    {
      :local first 123
      :local second 456
      :local result1
      :local result2
    
      :set result1 [$getSum $first $second debug=1]
      :set result2 [$getSum $second 789]
      :put ("results are ".$result1." and ".$result2)
    }
    


    1. BrookXVII Автор
      04.09.2022 23:40

      Я вроде не писал, что использую :parse для функций. Почти все они развернуты, так как Вы и описали.

      Из скрипта можем вызвать функцию, развернутую в глобальной переменной, выполнить код из :parse, или вызвать другой скрипт.

      Вот внутри функций есть места где вызывается код методом :parse или :execute, а можно и вместе...

      :set result "[[:parse [system script get $calledFunctionName source]] queryID=$queryID queryChatID=$queryChatID...]"
      :execute script=$result


      1. Chupaka
        06.09.2022 09:19
        +1

        Да, действительно... Глаз замылился, а примеры у вас только с парсингом, без прямого вызова — вот меня даже поиск по тексту перед отправкой комментария не спас :)


  1. Valser
    05.09.2022 00:49

    Какая то реклама микротик, то что описано, понадобится 0,01 процентов тех кто купил микротик, а тем кто не купил, но им это нужно, реализуют это куда более лучшими средствами. Про телеграмм, просто промолчит, особенно про api, на 1 курсе, можно построить лучше, на собственный платформе, просто потому что телеграмм это мессенджер в первую очередь и таким он создавался, а то что там появилось потом api, не значит что оно хорошее/лучшее/удобное ( не нужное вычеркнуть), поэтому совет новичкам, попробуйте не микротик и не телеграмм, перспектив больше.


    1. BrookXVII Автор
      05.09.2022 01:20
      +7

      Если мой код поможет 0,01% тех, кто купил устройство, считай уже не зря старался. Микротик вообще не для слабонервных, его домой просто так никто не купит. Тут больше корпоративный сегмент. А Телеграм давно перестал быть просто мессенджером, это социальная сеть. И скорее всего так и задумывался, если учесть кто его создатель.


      1. jstbot
        05.09.2022 14:48
        +1

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


  1. net_racoon
    05.09.2022 09:27
    +1

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

    Главное непонятно, что сделать то хотите, для чего это? Мониторить железку- ставите полноценную NMS и мониторите, с уведомлениями и т.п. Управлять- вам там целый набор: SSH, WinBox. Web. Автоматизация- ансибл и вперед.

    Почему у меня горит? Щас кто-то по вашей статье накостылит у себя в сети, а потом кому-то это разгребать. Или после вас.

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


    1. Tarakanator
      05.09.2022 11:40
      +2

      Мониторить железку- ставите полноценную NMS и мониторите, с уведомлениями и т.п

      Ставить полноценную железку, чтоб она отвечала на запрос кто дома?
      Всё решается одним микротом


      бот запускает скрипт на микроте, микрот смотрит аренду IP смартфонами. Если аренда жива-человек дома.

      Зачем брать микротик, если можно взять подходящий инструмент для этого?

      Если вам нужно закрутить одну гайку, вы берёте гаечный ключ(или даже плоскогубцы) или профессиональный пневмоинструмент с компрессорной станцией?


      1. net_racoon
        05.09.2022 13:15

        Ставить полноценную железку, чтоб она отвечала на запрос кто дома? Всё решается одним микротом

        А где в статье про это написано? Либо надо писать, что не для использования в продакшене. Чтобы эникейщик, который чудом освоил гугл не нес это в сеть.


        1. Tarakanator
          05.09.2022 14:55

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


        1. sirota
          06.09.2022 06:08
          +1

          Собственно, а можно обоснование почему нельзя в прод?


          1. net_racoon
            06.09.2022 09:16

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

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

            Приходишь в такие организации, а там дышать на это поделие боятся: "Вдруг мы обновимся, а там скрипт сломается!".


            1. sirota
              06.09.2022 09:54

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

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


              1. net_racoon
                06.09.2022 10:21

                И с готовыми решениями нет уверенности что при обновлении не сломается. 

                Конечно нет. Но обычно перед обновлением известно что может сломаться и если что-то сломалось у вас обычно есть ТП, коммьюнити, форумы, чаты и т.п. где вам могут помочь.

                Да конечно с распространённым софтом в плане поддержки проще, но опять же иногда оно не подходит по тем или иным обстоятельствами. Бывает не устраивает гибкость и зависимость от кого-то.

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

                Ну начнем с того, что в крупном бизнесе вряд ли будут использовать микротики. Я представляю что в крупном бизнесе. Обычно там если что-то нужно особенное, создается отдел разработки, где там делается все по уму, документируется, поддерживается и т.д. Именно поэтому они стараются по максимуму использовать то что уже есть, ибо разработка своего (не на коленке, а как надо) стоит дороже.


            1. BrookXVII Автор
              06.09.2022 11:30

              С таким подходом любой софт можно назвать костыльной самоделкой =) Вы код откройте для начала. Я что зря писал про архитектуру и модульность? Там первокурсник разберется.

              Микротик - это в первую очередь RouterOS. А раз это ОС, то под неё можно писать код. Замечу - код открыт. Что-то не устраивает - перепиши. Если оно вообще не надо - удали и работай через Winbox.

              Многие недооценивают возможности Микротик, потому что не умеют его готовить. А в продакшене редко стоят какие-нибудь HAP. У нас к примеру CCR1036, у которого на борту 36 процессорных ядер и 4 гига памяти. На нем куча vLan, DHCP серверов, динамические очереди и много другого. Он бота вообще не замечает, как нагрузку. Причем бот стабильно работает даже слабеньких точках доступа.

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

              Вам большое спасибо за Ваше мнение. Я, безусловно, его уважаю и полностью поддерживаю в части опасности использования костылей, но тут совсем другой случай. Сам в продакшене использую большие серьезные системы, в том числе SCCM и всю линейку SC, для мониторинга Zabbix + Grafana. И еще много других систем. Есть так-же Cisco в стеках и куча Juniper-ов. Но микротик мне нравится больше...


  1. BrookXVII Автор
    05.09.2022 14:47

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

    И работает это всё прямо в среде маршрутизатора. Не надо разворачивать и настраивать сторонние системы.


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


    1. net_racoon
      05.09.2022 16:13

      Какая прелесть. Вот про это я и писал. Мои искреннее сочувствие тому, кто будет после вас это разгребать.


      1. BrookXVII Автор
        05.09.2022 17:15

        =)


    1. net_racoon
      06.09.2022 09:43

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

      А остальные устройства вы как мониторите, которые не на РоутерОС сделаны? Там свои костыли?

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

      AAA

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

      Dot1x

      И работает это всё прямо в среде маршрутизатора.

      Который в тоже время должен трафик маршрутизировать

      Меня вдруг осенило, а вы случайно не Сааб?


      1. BrookXVII Автор
        06.09.2022 11:34

        Меня вдруг осенило, а вы случайно не Сааб?

        Этот момент поясните пожалуйста, я его не понял...