Как стать автором
Обновить

И снова Mikrotik, Telegram и боты

Здравствуйте. Статья не полностью претендует на право быть оригинальной — скорее, это усовершенствование скрипта, описанного в статье dimonw Удалённое включение скриптов Mikrotik из Telegram.
В общем, сделал себе бота по примеру в вышеуказанной статье. Но меня жутко напрягал тот момент, что постоянно fetch'ем скачивается файл на драгоценную флешку, и потом парсится.
Поэтому, немного покурил Wiki/Scripting, и у меня получилось обойтись без файла.

Принципиальные изменения внесены в самом начале скрипта — вместо того, чтобы скачивать fetch'ем файл, и потом его парсить, как в оригинальном скрипте:

:tool fetch url=("https://api.telegram.org/".$botID."/getUpdates") ;
:global content [/file get [/file find name=getUpdates] contents] ;


воспользуемся нововведением RoS 6.43
Since RouterOS v6.43 it is possible to save the result of fetch command to a variable.

и напишем команду, которая загоняет данные напрямую в переменную content, без скачивания файла на флешку:

:global content [/tool fetch url=("https://api.telegram.org/".$botID."/getUpdates") as-value output=user];


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

data={"ok":true,"result":[]};
downloaded=0;
duration=00:00:01;
status=finished;
total=0


а нам нужно проверить длину полученного сообщения на предмет того, поступала роутеру какая-нибудь команда, или нет, то есть длину поля data. В оригинальном скрипте это делается командой

:if ( [/file get [/file find name=getUpdates] size] > 50 ) do={


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

/tool fetch url=("https://api.telegram.org/".$botID."/getUpdates")


она вернёт значение 5 — количество элементов массива. Ну, ничего страшного — переприсвоим переменной content значение одного только поля data:

:set content ($content ->"data")


Теперь у нас в переменной content находится не массив

data={"ok":true,"result":[]};
downloaded=0;
duration=00:00:01;
status=finished;
total=0


а строка
{"ok":true,"result":[]};


что нам и нужно. Теперь можем писать условие:

:if ([:len $content] > 23 ) do={


23 — потому что длина строки, которую нам возвращает Telegram, в случае, если боту не поступила ни одна команда — {"ok":true,"result":[]} — составляет как раз 23 символа.
Ещё, в сравнении с оригинальным скриптом, изменена строка

:local message [:pick $content ($startLoc + 1) $endLoc] ;


и выброшена ненужная переменная $lastEnd, вместо неё используется параметр -1, как и положено по документации.

В результате, всё работает, как задумано, но без скачивания файла и израсходования ресурса флешки.
Попутно, как довольно-таки приятный бонус, отсутствует так ранее напрягавший спам в логе каждых 10-20-30 секунд (или какой там у вас интервал опроса Телеграма) в виде:
22:33:09 info fetch: file "getUpdates" downloaded

Скрипт целиком у меня выглядит так:

Тело скрипта
:global content [/tool fetch url=("https://api.telegram.org/".$botID."/getUpdates") as-value output=user];
:set content ($content ->"data")
:global startLoc 0;
:global endLoc 0;
 
:if ([:len $content] > 23 ) do={
 
:set startLoc  [:find $content "update_id" -1 ] ;
:set startLoc ( $startLoc + 11 ) ;
:local endLoc [:find $content "," $startLoc] ;
:local messageId ([:pick $content $startLoc $endLoc] + (1));
:put [$messageId] ;
:#log info message="updateID $messageId" ;
 
:set startLoc  [:find $content "text" -1 ] ;
:set startLoc ( $startLoc  + 7 ) ;
:local endLoc [:find $content "," ($startLoc)] ;
:set endLoc ( $endLoc - 1 ) ;
:local message [:pick $content ($startLoc + 1) $endLoc] ;
:put [$message] ;
:log warn message="Command $message received";
 
:set startLoc  [:find $content "chat" -1 ] ;
:set startLoc ( $startLoc + 12 ) ;
:local endLoc [:find $content "," $startLoc] ;
:local chatId ([:pick $content $startLoc $endLoc]);
:put [$chatId] ;
:#log info message="chatID $chatId ";
 
:if (($chatId = $myChatID) and (:put [/system script find name=$message] != "")) do={
:system script run $message} else={:tool fetch url=("https://api.telegram.org/".$botID."/sendmessage\?chat_id=".$chatId."&text=I can't talk with you. ") keep-result=no};
:tool fetch url=("https://api.telegram.org/".$botID."/getUpdates\?offset=$messageId") keep-result=no;


Имейте в виду, что здесь описана лишь модификация части скрипта; за полной инструкцией по созданию Telegram-бота обращайтесь к оригинальной статье.

Manual:Scripting
habr.com/ru/post/314108
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.