Удалённое включение скриптов Mikrotik из Telegram v 2.0

    Всех с прошедшим праздником. Данная тема является более лучшей версией того, что я писал в далеком 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

    Комментарии 20

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

            0
            кавычки не те :) при вставке кода видимо заменило. сейчас исправлю.
            проверьте должны быть такие и дальше по коду аналогично.
            :global botID "botXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXX" ;
            :global myChatID "YYYYYY" ;
              0
              поехало! спасибо!
              Вообще конечно хорошая фича.
        0
        Подскажите а как при этом решаете проблему доступа к api.telegram.org а то он вроде как заблокирован.
          0
          Ну по началу пока провайдер не научился нормально блокировать, отшибал их заглушку и все замечательно работало. Но через пол года они начали как то жестко блокать, (даже переписал скрипты под SLACK. Но не весь функционал получился нормальным) разбираться уже не стал, просто кинул FreeVpn, чисто для телеги на Mikrotik. Работает все отлично.
            0
            Если не затруднит не подскажете какой бесплатный VPN вы используете?
            0
            вот так
            image
              0
              Ну CHR это я так понимаю VPN сервер на AWS ?).
              Я не стал заморачиваться, пользую халявный.
                0
                так же пользую халявный))
                AWS на год халявный, потом перерегать и залить конфиг не долго.
                  0
                  я слишком ленивый. :) этож через год какие то манипуляции делать надо будет. Но спасибо за инфо, надо будет посмотреть :) давно хотел познакомиться с AWS.
            +1
            ИМХО использование :while ( true ) без задержки — лишняя нагрузка на ваш роутер и потеря встроенного функционала scheduler, но каждому своё.
            В любом случае, если вы решили использовать этот подход — лучше не писать response на диск, учитывая что у вас там одно короткое сообщение.
            :local httpResponse [:tool fetch url=$requestUrl as-value output=user]
            :local content ($httpResponse->"data");
              0
              Спасибо за совет.
              Заменить этот код
              :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]


              На этот
              :local httpResponse [:tool fetch url="https://api.telegram.org/$botID/getUpdates\?offset=$messageId&limit=1&allowed_updates=message&timeout=60" as-value output=user];
              :local content ($httpResponse->"data");

              0
              Попробовал немного изменить код скрипта, в результате теперь приходят уведомления о логине на устройство и о подключении юзеров по 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
              }
              }


              P.S если в шедульке указать запуск каждые 5 минут и быстро залогиниться\разлогиниться, то отобразится только одно сообщение о логоне.
                0

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

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

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


                  P.S

                  починил!
                  :global lastTime
                  :global output
                  :global mtIdentity [/system identity get name];
                  :global botID «botxxxxxxxxxx:yyyyyyyyyyyyyy»;
                  :global myChatID «zzzzzzzzzzz»;

                  :local LogGet [ :toarray [ /log find topics~«system» || message~«login failure» || message~"[Ff]ailure" ] ];
                  :local LogGet [ :toarray [ /log find topics~«system» || message~«logged» || message~"[Ll]ogged" ] ];
                  :local LogGet [ :toarray [ /log find topics~«system» || 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

                  }
                  }


                  только теперь все события с тикетом system будут лететь в телегу))
                    0
                    Можно добавить искомые строки logged и connected в одну переменную:
                    LogGet
                    :local LogGet [ :toarray [ /log find topics~«system» || message~«login failure» || message~«logged» || message~«connected» || message~"[Ff]ailure" ] ];

                    И что бы не заморачиваться с блокировками телеги можно использовать push, я использую pushover_net.
                0
                Столкнулся с проблемой, на MikroTik hAP ac lite (RB952Ui-5ac2nD-TC), при отправке боту не поддерживаемой команды, в первые 2 раза от отправляет корректный ответ, однако после этого, идёт «зацикливание» скрипта, растёт загрузка CPU, и бот начинает отправлять по 3-7 сообщений в ответ. Прошу пользователей скрипта проверить у себя, и если баг есть, я был бы вам очень благодарен, за помощь в его исправлении.

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

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

                Самое читаемое