Спасибо большое за Ваш труд ! Очень хороший и нужный скрипт.
Для автора - есть универсальный JSON-парсер от Чупакабры, который прекрасно парсит данные из JSON в многомерные массивы.
https://habr.com/ru/post/337978/
https://github.com/Winand/mikrotik-json-parser
Я использую его постоянно, для распарсивания ответов от различных сайтов или аппаратуры.
Вы могли бы использовать его для парсинга в Вашем скрипте.
А вообще мне очень нравится Ваш скрипт. Написан профессионально. Жму Вам руку и снимаю шляпу ! Так держать, будем ждать Ваших новых скриптов, полезных всем.
Удаленный запуск скриптов через Телеграм
Правила форума
Уважаемые Пользователи форума, обратите внимание!
Ни при каких обстоятельствах, Администрация форума, не несёт ответственности за какой-либо, прямой или косвенный, ущерб причиненный в результате использования материалов, взятых на этом Сайте или на любом другом сайте, на который имеется гиперссылка с данного Сайта. Возникновение неисправностей, потерю программ или данных в Ваших устройствах, даже если Администрация будет явно поставлена в известность о возможности такого ущерба.
Просим Вас быть предельно осторожными и внимательными, в использовании материалов раздела. Учитывать не только Ваши пожелания, но и границы возможностей вашего оборудования.
Уважаемые Пользователи форума, обратите внимание!
Ни при каких обстоятельствах, Администрация форума, не несёт ответственности за какой-либо, прямой или косвенный, ущерб причиненный в результате использования материалов, взятых на этом Сайте или на любом другом сайте, на который имеется гиперссылка с данного Сайта. Возникновение неисправностей, потерю программ или данных в Ваших устройствах, даже если Администрация будет явно поставлена в известность о возможности такого ущерба.
Просим Вас быть предельно осторожными и внимательными, в использовании материалов раздела. Учитывать не только Ваши пожелания, но и границы возможностей вашего оборудования.
-
- Сообщения: 1601
- Зарегистрирован: 15 сен 2017, 09:03
-
- Сообщения: 1601
- Зарегистрирован: 15 сен 2017, 09:03
Вопрос такой: если ставлю исполнение Вашего скрипта-парсера в Планировщике скажем не раз в минуту, а раз в 30 секунд, он начинает выполнять скрипт не один а два или более раз подряд. Можно как то подправить этот косяк ?
фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
viewtopic.php?f=14&t=13947
-
- Сообщения: 1601
- Зарегистрирован: 15 сен 2017, 09:03
И ещё вопрос: можете ли Вы доработать скрипт, чтобы он мог исполнять не только процедуры (запуская одноимённые скрипты-команды из реппозитория роутера), но и функции из окружения переменных с параметрами. То есть команды-функции пользователя типа [$Function var1, var2] ?
фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
viewtopic.php?f=14&t=13947
- drpioneer
- Сообщения: 152
- Зарегистрирован: 30 май 2013, 10:20
Приветствую!
2. По меньшему периоду времени исполнения скрипта: специально для вас сделал такую возможность и устранил проблему с повторным исполнением скрипта.
Проверяйте...
3. По доработке скрипта на предмет исполнения команд-функций: к моему стыду я не сильно знаком с этой темой, поэтому не до конца понимаю, что нужно сделать... Накидайте ссылок для погружения в этот вопрос... А там посмотрим...
Заранее спасибо.
1. Встречный вопрос по универсальному парсеру от Чупакабры: какие преимущества от его использования по сравнению с тем, что уже имеется в скрипте?Sertik писал(а): ↑30 сен 2021, 12:04 Для автора - есть универсальный JSON-парсер от Чупакабры, который прекрасно парсит данные из JSON в многомерные массивы.
Я использую его постоянно, для распарсивания ответов от различных сайтов или аппаратуры.
Вы могли бы использовать его для парсинга в Вашем скрипте.
.....
Вопрос такой: если ставлю исполнение Вашего скрипта-парсера в Планировщике скажем не раз в минуту, а раз в 30 секунд, он начинает выполнять скрипт не один а два или более раз подряд. Можно как то подправить этот косяк ?
.....
И ещё вопрос: можете ли Вы доработать скрипт, чтобы он мог исполнять не только процедуры (запуская одноимённые скрипты-команды из реппозитория роутера), но и функции из окружения переменных с параметрами. То есть команды-функции пользователя типа [$Function var1, var2] ?
2. По меньшему периоду времени исполнения скрипта: специально для вас сделал такую возможность и устранил проблему с повторным исполнением скрипта.
Код: Выделить всё
# Script remote activation script via Telegram by drPioneer
# https://forummikrotik.ru/viewtopic.php?p=78085
# tested on ROS 6.48.3
# updated 2021/10/01
:global oldMsg;
:do {
:local botID "botXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
:local myChatID "-XXXXXXXXX";
# Telegram messenger response parsing function by Dimonw
# https://habr.com/ru/post/482802/
:local parse do={
:local variaMod ("\"".$variable);
:local startLoc ([:find $content $variaMod -1] + [:len $variaMod] + 2);
:local commaLoc ([:find $content "," $startLoc]);
:local brakeLoc ([:find $content "}" $startLoc]);
:local endLoc $commaLoc;
:local startSymbol [:pick $content $startLoc];
:if ($brakeLoc != 0 and ($commaLoc = 0 or $brakeLoc < $commaLoc)) do={ :set endLoc $brakeLoc; };
:if ($startSymbol = "{") do={ :set endLoc ($brakeLoc + 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];
:return $message;
}
# UNIX time conversion function to normal view by Pepelxl
# https://forummikrotik.ru/viewtopic.php?t=11636
:local unixTime do={
:local dateY ($timeStamp / 31436000 + 1970);
:local dateM (($dateY - 1969) / 4);
:local dateD (($timeStamp / 86400 - $dateM) % 365);
:local days [:toarray (31,28,31,30,31,30,31,31,30,31,30,31)];
:local months [:toarray ("jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec")];
:if ($dateY % 4 = 0) do={ :set ($days->1) 29; }
do {
:for i from=0 to=11 do={
:if (($days->$i) > $dateD) do={
:set $dateM ($i);
:set $dateD ($dateD + 1);
:break;
} else={ :set $dateD ($dateD - ($days->$i)); }
}
} on-error={}
:local timeS ($timeStamp % 86400);
:local timeH ($timeS / 3600);
:local timeM ($timeS % 3600 / 60);
:set $timeS ($timeS - $timeH * 3600 - $timeM * 60);
:local normalTime (($months->$dateM)."/");
:if ($dateD < 10) do={ :set $normalTime ($normalTime."0".[:tostr $dateD]."/"); } else={ :set $normalTime ($normalTime.[:tostr $dateD]."/"); }
:set $normalTime ($normalTime.[:tostr $dateY]." ");
:if ($timeH < 10) do={ :set $normalTime ($normalTime."0".[:tostr $timeH].":"); } else={ :set $normalTime ($normalTime.[:tostr $timeH].":"); }
:if ($timeM < 10) do={ :set $normalTime ($normalTime."0".[:tostr $timeM].":"); } else={ :set $normalTime ($normalTime.[:tostr $timeM].":"); }
:if ($timeS < 10) do={ :set $normalTime ($normalTime."0".[:tostr $timeS]); } else={ :set $normalTime ($normalTime.[:tostr $timeS]); }
:put ([:totime $normalTime]);
:return $normalTime;
}
# Main body of the script
:local nameID [ /system identity get name; ];
:local dateNow [ /system clock get date; ];
:local timeNow [ /system clock get time; ];
:local httpResponse [ /tool fetch url="https://api.telegram.org/$botID/getUpdates\?offset=-1&limit=1&allowed_updates=message&timeout=60" as-value output=user; ];
:local content ($httpResponse->"data");
:if ([:len $content] > 30) do={
:local msgId [$parse content=$content variable="update_id"];
:local message [$parse content=$content variable="text" quotas=true];
:set message ([:pick $message ([:find $message "/"] + 1) ([:len $message])]);
:local chat [$parse content=$content variable="chat"];
:local chatId [$parse content=$chat variable="id"];
:local userName [$parse content=$content variable="username"];
:local dateTime [$parse content=$content variable="date"];
:set dateTime ($dateTime + [ /system clock get gmt-offset; ]);
:local normTime [$unixTime timeStamp=$dateTime];
:put ("Current time on router:\t $dateNow $timeNow");
:put ("Last message from $userName: time=$normTime, id=$msgId, text=$message.");
:if (($normTime ~ $dateNow) && ([:totime [:pick $normTime ([:find $normTime " "] + 1) ([:find $normTime " "] + 9)]] > ($timeNow - 00:00:30))) do={
:put ("Right time to activation script.");
:if ($message != $oldMsg) do={
:if (($chatId = $myChatID) && ([/system script find name=$message] != "")) do={
:put ("Telegram user $userName activated script '$message'.");
:log warning ("Telegram user $userName activated script '$message'.");
/system script run $message;
:set oldMsg ($message);
/tool fetch keep-result=no url="https://api.telegram.org/$botID/sendmessage\?chat_id=$chatId&text=$nameID: '$message' command accepted.";
} else={ :put ("Not all conditions activation script are met."); }
} else={ :put ("Command has already been executed."); }
} else={ :put ("Bad time to activation script."); :set oldMsg (""); }
}
} on-error={ :put ("Script error: 1 - message could have been sent a long time ago. 2 - check whether 'botID' & 'myChatID' variables are specified correctly."); }
3. По доработке скрипта на предмет исполнения команд-функций: к моему стыду я не сильно знаком с этой темой, поэтому не до конца понимаю, что нужно сделать... Накидайте ссылок для погружения в этот вопрос... А там посмотрим...
Заранее спасибо.
-
- Сообщения: 1601
- Зарегистрирован: 15 сен 2017, 09:03
К этому скрипту парсер Чупакабры ничего не добавит. Я прислал его на будущее. Когда нужно парсить JSON не стоит уже изобретать велосипед и выискивать информацию командами :find, вырезая куски :peek и т.д... Если, конечно нужно найти в JSON ответе один - два параметра, можно обойтись и своими силами ... А когда JSON возвращает много нужных данных - парсер Чупакабры незаменимая вещь. Ни о чём не надо думать - подсовываешь парсеру JSON, получаешь отпарсенный ключевой массив данных.
По поводу функций. Функция отличается от процедуры тем, что может иметь аргументы и может возвращать результат своей работы. Смотрите. Ваш парсер отлично справляется с исполнением скриптов чьи имена совпадают с пересланными на исполнение. Например посылаем /reboot. Если в репозитории роутера есть скрипт с таким именем - парсер его найдет и выполнит. А как быть, если есть функция ? У которой может быть N-ное число параметров и которая может вернуть результат своей работы в точку из которой она вызвана ?
Общая запись вызова функции, заранее размещенной в репозитории роутера такая [$FuncName var1=val1, var2=var2 ...].
Параметры функций (var) могут быть именованными и не содержать имен, тогда имеет значение их порядок 1,2,3 и т.д...
Для использования функции она должна быть объявлена переменной глобал, а потом вызвана.
:global $FuncName; [$FuncName var1=val1, var2=var2 ...]
Функция может вернуть результат своей работы, с помощью команды :return, в виде числа, строки, массива и т.д... то есть данных любого типа.
:global $FuncName; local answer [$FuncName var1=val1, var2=var2 ...]
В переменной answer будет результат.
Да ещё и надо понимать, что функция может быть аргументом другой функции, а также в РоутерОс поддерживается рекурсивный вызов функций ...
Честно говоря, реализация поддержки функций в Телеграмм-парсере представляется очень сложным, а может и не возможным делом. Возможно проще наделать скриптов с разными именами, содержащих разные значения нужных параметров и запускать их как процедуры. Возврат значений представляется вообще не реализуемой задачей ....
Наверное, я переборщил с вопросом о возможности реализации подержки функций в парсере Телеграмм - ну их к шуту, можно вполне без них обойтись ...
Спасибо, всем пригодиться. Ткните носом где эта проблема была в тексте скрипта (для повышения образованности).устранил проблему с повторным исполнением скрипта
По поводу функций. Функция отличается от процедуры тем, что может иметь аргументы и может возвращать результат своей работы. Смотрите. Ваш парсер отлично справляется с исполнением скриптов чьи имена совпадают с пересланными на исполнение. Например посылаем /reboot. Если в репозитории роутера есть скрипт с таким именем - парсер его найдет и выполнит. А как быть, если есть функция ? У которой может быть N-ное число параметров и которая может вернуть результат своей работы в точку из которой она вызвана ?
Общая запись вызова функции, заранее размещенной в репозитории роутера такая [$FuncName var1=val1, var2=var2 ...].
Параметры функций (var) могут быть именованными и не содержать имен, тогда имеет значение их порядок 1,2,3 и т.д...
Для использования функции она должна быть объявлена переменной глобал, а потом вызвана.
:global $FuncName; [$FuncName var1=val1, var2=var2 ...]
Функция может вернуть результат своей работы, с помощью команды :return, в виде числа, строки, массива и т.д... то есть данных любого типа.
:global $FuncName; local answer [$FuncName var1=val1, var2=var2 ...]
В переменной answer будет результат.
Да ещё и надо понимать, что функция может быть аргументом другой функции, а также в РоутерОс поддерживается рекурсивный вызов функций ...
Честно говоря, реализация поддержки функций в Телеграмм-парсере представляется очень сложным, а может и не возможным делом. Возможно проще наделать скриптов с разными именами, содержащих разные значения нужных параметров и запускать их как процедуры. Возврат значений представляется вообще не реализуемой задачей ....
Наверное, я переборщил с вопросом о возможности реализации подержки функций в парсере Телеграмм - ну их к шуту, можно вполне без них обойтись ...
фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
viewtopic.php?f=14&t=13947
- drpioneer
- Сообщения: 152
- Зарегистрирован: 30 май 2013, 10:20
Очень кратко: введена глобальная переменная oldMsg, которая хранит в себе последнюю выполненную скриптом команду. Теперь при повторном запуске скрипта, перед исполнением команды производится проверка oldMsg и принятие решения об её исполнении или неисполнении. Как-то так...
-
- Сообщения: 1601
- Зарегистрирован: 15 сен 2017, 09:03
Большое спасибо. Теперь можно запускать скрипт чаще чем раз в минуту. Пробовал раз в 15 секунд - работает безупречно. ! Повторных исполнений не было.
фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
viewtopic.php?f=14&t=13947
-
- Сообщения: 3
- Зарегистрирован: 01 апр 2021, 15:02
-
- Сообщения: 1601
- Зарегистрирован: 15 сен 2017, 09:03
Приветствую и подтверждаю !
Скрипт действительно перестал работать . Может в Телеграмм что-то изменили ?
Очень нужный был и отлично работающий скрипт ... Поправьте, пожалуйста, ув. Dr.Pioneer.
P/S При исполнении из терминала мне также выдаёт:
Last message from "result":[{"update_id":203788784: time=oct/20/2022 10:22:52, id=203788784, text=example.
Bad time to activation script.
Скрипт действительно перестал работать . Может в Телеграмм что-то изменили ?
Очень нужный был и отлично работающий скрипт ... Поправьте, пожалуйста, ув. Dr.Pioneer.
P/S При исполнении из терминала мне также выдаёт:
Last message from "result":[{"update_id":203788784: time=oct/20/2022 10:22:52, id=203788784, text=example.
Bad time to activation script.
фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
viewtopic.php?f=14&t=13947
-
- Сообщения: 1601
- Зарегистрирован: 15 сен 2017, 09:03
Пришлось самому копать и поправить Ваш скрипт. Не долго думая вставил туда подправленную локальную функцию FuncUnixTimeToFormat, которую когда то взял у pepelxl с его разрешения и переделал под себя. Теперь весь основной скрипт удаленного запуска скриптов через Telegram работает правильно вроде как. Проверяйте ...
Код: Выделить всё
# Script remote activation script via Telegram by drPioneer
# https://forummikrotik.ru/viewtopic.php?p=78085
# tested on ROS 6.48
# updated 2021/04/05
:do {
:global botID;
:global myChatID;
# Telegram messenger response parsing function by Dimonw
# https://habr.com/ru/post/482802/
:local parse do={
:local variaMod ("\"".$variable);
:local startLoc ([:find $content $variaMod -1] + [:len $variaMod] + 2);
:local commaLoc ([:find $content "," $startLoc]);
:local brakeLoc ([:find $content "}" $startLoc]);
:local endLoc $commaLoc;
:local startSymbol [:pick $content $startLoc];
:if ($brakeLoc != 0 and ($commaLoc = 0 or $brakeLoc < $commaLoc)) do={ :set endLoc $brakeLoc; };
:if ($startSymbol = "{") do={ :set endLoc ($brakeLoc + 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];
:return $message;
}
# год не ограничен столетием
# usial [$FuncUnixTimeToFormat "timeStamp", "type"]
# type:
# "unspecified" - month/dd/yyyy <only> ((Mikrotik sheduller format)
# 1 - yyyy/mm/dd hh:mm:ss
# 2 - dd:mm:yyyy hh:mm:ss
# 3 - dd month yyy hh mm ss
# 4 - yyyy month dd hh mm ss
#5 - month/dd/yyyy-hh:mm:ss (Mikrotik sheduller format)
:local FuncUnixTimeToFormat do={
:local decodedLine ""
:local timeStamp $1
:local timeS ($timeStamp % 86400)
:local timeH ($timeS / 3600)
:local timeM ($timeS % 3600 / 60)
:set $timeS ($timeS - $timeH * 3600 - $timeM * 60)
:local dateD ($timeStamp / 86400)
:local dateM 2
:local dateY 1970
:local leap false
:while (($dateD / 365) > 0) do={
:set $dateD ($dateD - 365)
:set $dateY ($dateY + 1)
:set $dateM ($dateM + 1)
:if ($dateM = 4) do={:set $dateM 0
:if (($dateY % 400 = 0) or ($dateY % 100 != 0)) do={:set $leap true
:set $dateD ($dateD - 1)}} else={:set $leap false}}
:local months [:toarray (0,31,28,31,30,31,30,31,31,30,31,30,31)]
:if (leap) do={:set $dateD ($dateD + 1); :set ($months->2) 29}
do {
:for i from=1 to=12 do={:if (($months->$i) >= $dateD) do={:set $dateM $i; :set $dateD ($dateD + 1); break;} else={:set $dateD ($dateD - ($months->$i))}}
} on-error={}
:local tmod
:if ([:len $2]!=0) do={:set $tmod $2} else={:set $tmod (:nothing)}
:local s "/"
:local nf true
:local mstr {"jan";"feb";"mar";"apr";"may";"jun";"jul";"aug";"sep";"oct";"nov";"dec"}
:local strY [:tostr $dateY]
:local strMn
:local strD
:local strH
:local strM
:local strS
:if ($nf) do={
:if ($dateM > 9) do={:set $strMn [:tostr $dateM]} else={:set $strMn ("0".[:tostr $dateM])}
:if ($dateD > 9) do={:set $strD [:tostr $dateD]} else={:set $strD ("0".[:tostr $dateD])}
:if ($timeH > 9) do={:set $strH [:tostr $timeH]} else={:set $strH ("0".[:tostr $timeH])}
:if ($timeM > 9) do={:set $strM [:tostr $timeM]} else={:set $strM ("0".[:tostr $timeM])}
:if ($timeS > 9) do={:set $strS [:tostr $timeS]} else={:set $strS ("0".[:tostr $timeS])}
} else={
:set strMn [:tostr $dateM]
:set strD [:tostr $dateD]
:set strH [:tostr $timeH]
:set strM [:tostr $timeM]
:set strS [:tostr $timeS]
}
do {
:if ([:len $tmod]=0) do={:local mt ($mstr->($dateM - 1)); :set $decodedLine ("$mt/"."$strD/"."$strY"); break;}
:if ($tmod = 1) do={:set $decodedLine "$strY$s$strMn$s$strD $strH:$strM:$strS"; break;}
:if ($tmod = 2) do={:set $decodedLine "$strD$s$strMn$s$strY $strH:$strM:$strS"; break;}
:if ($tmod = 3) do={:set $decodedLine ("$strD ".($mstr->($dateM - 1))." $strY $strH:$strM:$strS"); break;}
:if ($tmod = 4) do={:set $decodedLine ("$strY ".($mstr->($dateM - 1))." $strD $strH:$strM:$strS"); break;}
:if ($tmod = 5) do={:local m ($mstr->($dateM - 1)); :set $decodedLine ("$m/"."$strD/"."$strY"." $strH:$strM:$strS"); break;}
} on-error={}
:return $decodedLine;
}
# Main body of the script
:local nameID [ /system identity get name; ];
:local dateNow [ /system clock get date; ];
:local timeNow [ /system clock get time; ];
:local httpResponse [ /tool fetch url="https://api.telegram.org/$botID/getUpdates\?offset=-1&limit=1&allowed_updates=message&timeout=60" as-value output=user; ];
:local content ($httpResponse->"data");
:if ([:len $content] > 30) do={
:local msgId [$parse content=$content variable="update_id"];
:local message [$parse content=$content variable="text" quotas=true];
:set message ([:pick $message ([:find $message "/"] + 1) ([:len $message])]);
:local chat [$parse content=$content variable="chat"];
:local chatId [$parse content=$chat variable="id"];
:local userName [$parse content=$content variable="username"];
:local dateTime [$parse content=$content variable="date"];
:set dateTime ($dateTime + [ /system clock get gmt-offset; ]);
:local normTime [$FuncUnixTimeToFormat $dateTime 5];
:log warning $normTime
:put ("Current time on router:\t $dateNow $timeNow");
:put ("Last message from $userName: time=$normTime, id=$msgId, text=$message.");
:if (($normTime ~ $dateNow) && ([:totime [:pick $normTime ([:find $normTime " "] + 1) ([:find $normTime " "] + 9)]] > ($timeNow - 00:01:00))) do={
:put ("Right time to activation script.");
:if (($chatId = $myChatID) && ([/system script find name=$message] != "")) do={
:put ("Telegram user $userName activated script '$message'.");
:log warning ("Telegram user $userName activated script '$message'.");
/system script run $message;
/tool fetch keep-result=no url="https://api.telegram.org/$botID/sendmessage\?chat_id=$chatId&text=$nameID: '$message' command accepted.";
} else={ :put ("Not all conditions activation script are met."); }
} else={ :put ("Bad time to activation script."); }
}
} on-error={ :put ("Script error: 1 - message could have been sent a long time ago. 2 - check whether 'botID' & 'myChatID' variables are specified correctly."); }
фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
viewtopic.php?f=14&t=13947