Всех с прошедшим праздником. Данная тема является более лучшей версией того, что я писал в далеком 2016 тут.

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

Закидываем скрипт в Mikrotik, меняем BotID и ChatID на свои и создаем на него schedule. Ставим параметр «Start Time» на startup (Запуск скрипта при старте.)
«Interval»: 00:00:00
В остальном все как и было.

Telegram-v2
:delay 10
:global mtIdentity [/system identity get name];
:global botID "botXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXX" ;
:global myChatID "YYYYYY" ;
:local chatId 0;
:local messageId 0;


:local parse do={
  :local startLoc ([:find $content $variable -1] + [:len $variable] + 2);
  :local commaLoc ([:find $content "," $startLoc] - 1 + 1);
  :local braceLoc ([:find $content "}" $startLoc] - 1 + 1);
  :local endLoc $commaLoc;
  :local startSymbol [:pick $content $startLoc]
  :if ($braceLoc != 0 and ($commaLoc = 0 or $braceLoc < $commaLoc)) do={
    :set endLoc $braceLoc;
  };
  :if ($startSymbol = "{") do={
    :set endLoc ($braceLoc + 1);
  };
  :if ($quotas = true) do={
    :set startLoc ($startLoc + 1);
    :set endLoc ($endLoc - 1);
  }
  :if ($endLoc < $startLoc) do={
    :set endLoc ($startLoc + 1);
  };
  :local message [:pick $content $startLoc $endLoc]
  #:log info $message;
  :return $message;
}


:while ( true ) do={
  :do {
    #:log info "https://api.telegram.org/$botID/getUpdates\?offset=$messageId&limit=1&allowed_updates=message&timeout=60";
    :tool fetch url=("https://api.telegram.org/$botID/getUpdates\?offset=$messageId&limit=1&allowed_updates=message&timeout=60") dst-path="getUpdates";
    :local content [/file get [/file find name=getUpdates] contents] ;
    #:log info $content;
    :if ([:len $content] > 30) do={
      :set messageId ([$parse content=$content variable="update_id"] + 1)
      :local message [$parse content=$content variable="text" quotas=true]
      :local chat [$parse content=$content variable="chat"]
      :local chatId [$parse content=$chat variable="id"]      
      
      :if (($chatId = $myChatID) and ([/system script find name=$message] != "")) do={
        :system script run $message;
      } else={
        :tool fetch url=("https://api.telegram.org/$botID/sendmessage\?chat_id=$chatId&text=$mtIdentity: Unknown command: $message") keep-result=no
      }
    }
  } on-error={}
};


За пару лет пользования был выявлен баг, по непонятным причинам слабенькие Mikrotik почему то останавливают скрипт, на более мощных работает без остановок.

Для этих целей накидал костыль WatchDog. тут меняем имя скрипта на то какое указывали выше. и ставим интервал перезапуска 5 минут. Каждые 5 минут наша «смотрящая собака» будет проверять скрипт, и если он не работает, то запустит его.

WatchDogT.me
:global scriptname "t.me"
:if ([:len [/system script job find script=$"scriptname"]] > 0) do={
:log info "$scriptname Already Running - killing old script before continuing"
:foreach counter in=[/system script job find script=$"scriptname"] do={
/system script job remove $counter
}
}
/system script run $scriptname


Ну и на десерт, скрипт взят с форума Mikrotik.
Отправляет важные топики из лога нам в телегу.

Закидываем скрипт в schedule и указываем интервал перезапуска каждые 5 минут, меняем BotID и ChatID на свои.

Notify-log
:global lastTime
:global output
:global mtIdentity [/system identity get name];
:global botID "botXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXX" ;
:global myChatID "YYYYYY" ;

:local LogGet [ :toarray [ /log find topics~"critical" || message~"login failure" || message~"[Ff]ailure" ] ] ;
:local LogtLineCount [ :len $LogGet ] ;
if ($LogtLineCount > 0) do={
   :local currentTime "$[ /log get [ :pick $LogGet ($LogtLineCount -1) ] time ]";
   :if ([:len $currentTime] = 10 ) do={
      :set currentTime [ :pick $currentTime 0 10 ];
   }
   :set output "$currentTime - $[/log get [ :pick $LogGet ($LogtLineCount-1) ] message ]";
   :if (([:len $lastTime] < 1) || (([:len $lastTime] > 0) && ($lastTime != $currentTime))) do={
      :set lastTime $currentTime ;
         :tool fetch url=("https://api.telegram.org/$botID/sendmessage\?chat_id=$myChatID&text=\"$mtIdentity\" :  $output") keep-result=no
   }
}


Получим результат:

image

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


  1. NeoBeZ
    04.01.2020 15:42

    не поехало, проверял на двух микротиках, первый домашний hex s, второй CHR поднятый у AWS. Тестил скрипт Notify-log, BotID\MyChatID поменял.
    отправка сообщений через tool fetch проходит успешно, в чём затык?


    1. dimonw Автор
      04.01.2020 15:47

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


      1. NeoBeZ
        04.01.2020 16:17

        всё правильно же?


        1. dimonw Автор
          04.01.2020 16:33

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

          :global botID "botXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXX" ;
          :global myChatID "YYYYYY" ;


          1. NeoBeZ
            04.01.2020 17:03

            поехало! спасибо!
            Вообще конечно хорошая фича.


  1. soyu22
    04.01.2020 19:37

    Подскажите а как при этом решаете проблему доступа к api.telegram.org а то он вроде как заблокирован.


    1. dimonw Автор
      04.01.2020 19:40

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


      1. soyu22
        05.01.2020 22:22

        Если не затруднит не подскажете какой бесплатный VPN вы используете?


    1. NeoBeZ
      04.01.2020 19:54

      вот так
      image


      1. dimonw Автор
        04.01.2020 19:59

        Ну CHR это я так понимаю VPN сервер на AWS ?).
        Я не стал заморачиваться, пользую халявный.


        1. NeoBeZ
          04.01.2020 20:03

          так же пользую халявный))
          AWS на год халявный, потом перерегать и залить конфиг не долго.


          1. dimonw Автор
            04.01.2020 20:06

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


  1. bewza
    05.01.2020 00:15

    ИМХО использование :while ( true ) без задержки — лишняя нагрузка на ваш роутер и потеря встроенного функционала scheduler, но каждому своё.
    В любом случае, если вы решили использовать этот подход — лучше не писать response на диск, учитывая что у вас там одно короткое сообщение.
    :local httpResponse [:tool fetch url=$requestUrl as-value output=user]
    :local content ($httpResponse->"data");


  1. NeoBeZ
    05.01.2020 13:02

    Попробовал немного изменить код скрипта, в результате теперь приходят уведомления о логине на устройство и о подключении юзеров по vpn, но failure-сообщения отвалились, что я делаю не так?

    код
    :global lastTime
    :global output
    :global mtIdentity [/system identity get name];
    :global botID «botXXXXXXXX:YYYYYYYYYYYYYYYYY»;
    :global myChatID «ZZZZZZZZZ»;

    :local LogGet [ :toarray [ /log find topics~«critical» || message~«login failure» || message~"[Ff]ailure" ] ];
    :local LogGet [ :toarray [ /log find topics~«account» || message~«logged» || message~"[Ll]ogged" ] ];
    :local LogGet [ :toarray [ /log find topics~«account» || message~«connected» || message~"[Cc]onnected" ] ];

    :local LogtLineCount [ :len $LogGet ];
    if ($LogtLineCount > 0) do={
    :local currentTime "$[ /log get [ :pick $LogGet ($LogtLineCount -1) ] time ]";
    :if ([:len $currentTime] = 10 ) do={
    :set currentTime [ :pick $currentTime 0 10 ];
    }
    :set output "$currentTime — $[/log get [ :pick $LogGet ($LogtLineCount-1) ] message ]";
    :if (([:len $lastTime] < 1) || (([:len $lastTime] > 0) && ($lastTime != $currentTime))) do={
    :set lastTime $currentTime;
    :tool fetch url=(«api.telegram.org$botID/sendmessage\?chat_id=$myChatID&text=\»$mtIdentity\": $output") keep-result=no
    }
    }


    1. Raivon
      05.01.2020 18:06

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


      1. NeoBeZ
        05.01.2020 20:06

        Согласен, но почему тогда обрабатываются вот эти две строчки?

        код
        :local LogGet [ :toarray [ /log find topics~«account» || message~«logged» || message~"[Ll]ogged" ] ];
        :local LogGet [ :toarray [ /log find topics~«account» || message~«connected» || message~"[Cc]onnected" ] ];


        1. haos
          06.01.2020 17:45

          Можно добавить искомые строки logged и connected в одну переменную:

          LogGet
          :local LogGet [ :toarray [ /log find topics~«system» || message~«login failure» || message~«logged» || message~«connected» || message~"[Ff]ailure" ] ];