Добрый день.
Sertik писал(а): ↑04 окт 2021, 13:31
1. Зачем в скрипте моя функция конвертер русского текста для Телеграмм ?
........
2. Однако у меня очень давно на всех роутерах стоит вот такой скрипт оповещения событий роутера в Телеграмм, добытый где-то на просторах интернет. К сожалению не знаю автора, но скрипт работает чудесно, ни разу не подводил и сам очень короткий. Вот такой:
........
1. Согласен. Тут я, пожалуй, переборщил. Не нужна она там.
2. Скрипт интересен и лаконичен. Кстати он имеет автора - AliceTails и представлен вот здесь:
https://www.reddit.com/r/mikrotik/comme ... _telegram/
Такими мне видятся его сильные и слабые стороны:
+ лаконично описана логика
+ не привязан к интервалу времени запуска и помнит время последней отправленной записи
- не умеет слать пачку записей, шлёт только последнюю найденную запись
- рассылает много ненужного (спамит)
А вот сильные и слабые стороны скрипта от Virtue:
+ не спамит (выбирает только важные для меня записи)
+ умеет присовокуплять к записям комментарии из DHCP
+ умеет слать пачку записей, если таковые имеются
- жестко привязан к периоду времени запуска и не запоминает последнюю отправленную запись
И вот у меня зачесались руки попытаться сделать скрипт, собравший в себе лучшее от этих двух... Интересно же...
Из скрипта Virtue дёрнул часть кода, прилепляющую к сообщениям комментарии из DHCP-lease и оформил её в функцию FindMacAddr. На вход этой функции прилетает строка. Функция производит поиск MAC-адреса и если таковой имеется, пытается подставить соответствующий ему комментарий из DHCP-lease. Плюс прикрутил поиск MAC-адреса в списке Bridge/Hosts с подстановкой соответствующего имени интерфейса. На выход функция отправляет эту же строку с найденным комментарием или без оного.
Для корректного взаимодействия с Telegram я задействовал предложенную во всеобщее пользование функцию SpaceToCode от Sertik, которая заменяет пробелы на "%20".
Для корректной работы с временными интервалами использовал функцию EpochTime от Jotne (
https://forum.mikrotik.com/viewtopic.ph ... 55#p790745 ), преобразующую дату и время Mikrotik в UNIX-time.
А дальше правка логики работы скрипта от AliceTails...
Получилась такая портянка:
Код: Выделить всё
# Telegram notification script by drPioneer
# https://forummikrotik.ru/viewtopic.php?p=81726#p81726
# tested on ROS 6.48.3
# updated 2021/10/14
:do {
:local botID "botXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
:local myChatID "-XXXXXXXXX";
# Function of searching comments for MAC-address by Virtue
# https://forummikrotik.ru/viewtopic.php?p=73994#p73994
:local FindMacAddr do={
:if ($1 ~"[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]:[0-F][0-F]") do={
:foreach idx in=[ /ip dhcp-server lease find dynamic=no disabled=no; ] do={
:local mac [ /ip dhcp-server lease get $idx mac-address; ];
:if ($1 ~"$mac") do={ :return ("$1 [$[ /ip dhcp-server lease get $idx comment; ]]."); }
}
:foreach idx in=[ /interface bridge host find; ] do={
:local mac [ /interface bridge host get $idx mac-address; ];
:if ($1 ~"$mac") do={ :return ("$1 [$[ /interface bridge host get $idx on-interface; ]]."); }
}
}
:return ($1);
}
# Function of converting SPACE to CODE by Sertik
# https://forummikrotik.ru/viewtopic.php?p=81481#p81481
:local SpaceToCode do={
:local char "";
:local string "";
:for idx from=0 to=([len $1]-1) do={
:set $char [:pick $1 $idx]
:if ($char=" ") do={ :set $char "%20"; }
:set $string ($string.$char);
}
:return ($string);
}
# Time translation function to UNIX-time by Jotne
# https://forum.mikrotik.com/viewtopic.php?t=75555#p790745
:local EpochTime do={
:local ds [ /system clock get date; ];
:local ts [ /system clock get time; ];
if ([:len $1] > 8) do={
:set ds "$[:pick $1 0 6]/$[:pick $ds 7 11]";
:set ts [:pick $1 7 15];
}
:local yesterday false;
if ([:len $1] = 8) do={
if ([:totime $1] > ts) do={ :set yesterday (true); }
:set ts $1;
}
:local months;
:if ((([:pick $ds 9 11]-1)/4) != (([:pick $ds 9 11])/4)) do={
:set months {"an"=0;"eb"=31;"ar"=60;"pr"=91;"ay"=121;"un"=152;"ul"=182;"ug"=213;"ep"=244;"ct"=274;"ov"=305;"ec"=335};
} else={
:set months {"an"=0;"eb"=31;"ar"=59;"pr"=90;"ay"=120;"un"=151;"ul"=181;"ug"=212;"ep"=243;"ct"=273;"ov"=304;"ec"=334};
}
:set ds (([:pick $ds 9 11]*365)+(([:pick $ds 9 11]-1)/4)+($months->[:pick $ds 1 3])+[:pick $ds 4 6]);
:set ts (([:pick $ts 0 2]*3600)+([:pick $ts 3 5]*60)+[:pick $ts 6 8]);
if (yesterday) do={ :set ds ($ds-1); }
:return ($ds*86400 + $ts + 946684800 - [ /system clock get gmt-offset; ]);
}
# Main body of Telegram notification script by AliceTails
# https://www.reddit.com/r/mikrotik/comments/onusoj/sending_log_alerts_to_telegram/
:global lastTimeLog;
:local outMsg "";
:local nameID [ /system identity get name; ];
:local logGet [ :toarray [ /log find ($topics ~"warning" || $topics ~"error" || $topics ~"critical" || $topics ~"caps" || $topics ~"wireless" || $message ~"logged in"); ]];
:local logCnt [ :len $logGet ];
if ([:len $lastTimeLog] < 1) do={
:put ("Time of the last log entry was not found.");
:set outMsg (">$[ /system clock get time; ] Telegram notification started.");
}
if ($logCnt > 0) do={
:local lastTime [$EpochTime [ /log get [:pick $logGet ($logCnt-1)] time; ]];
:local index 0;
:local tempTime;
:local tempMessage;
:local tempTopic;
:local unixTime;
:do {
:set index ($index + 1);
:set tempTime [ /log get [:pick $logGet ($logCnt - $index)] time; ];
:set tempTopic [ /log get [:pick $logGet ($logCnt - $index)] topics; ];
:set tempMessage [ /log get [:pick $logGet ($logCnt - $index)] message; ];
:set tempMessage (">".$tempTime." ".$tempMessage);
:local findMacMsg ([$FindMacAddr $tempMessage]);
:set unixTime [$EpochTime $tempTime];
if (($unixTime > $lastTimeLog) && (!(($tempTopic ~"caps" || $tempTopic ~"wireless" || $tempTopic ~"dhcp") && ($tempMessage != $findMacMsg)))) do={
:put $findMacMsg;
:set outMsg ($findMacMsg."%0A".$outMsg);
}
} while=(($unixTime > $lastTimeLog) && ($index < $logCnt));
:if (([:len $lastTimeLog] < 1) || (([:len $lastTimeLog] > 0) && ($lastTimeLog != $lastTime) && ([:len $outMsg] > 8) )) do={
:set lastTimeLog $lastTime;
:local urlString ("https://api.telegram.org/$botID/sendmessage\?chat_id=$myChatID&text=$nameID:%0A$outMsg");
:set urlString [$SpaceToCode $urlString];
:put ("Generated string for Telegram:\r\n".$urlString);
/tool fetch keep-result=no url=$urlString;
} else={ :put ("Nothing to send."); }
} else={ :put ("Necessary log entries were not found."); }
} on-error={ :put ("Script error: check whether 'botID' & 'myChatID' variables are specified correctly."); }
Вкратце пробегусь по коду:
1. В $logGet закидываются все потенциально интересные нам записи из LOGа. Если таких записей не нашлось, тогда работа скрипта завершается.
2. Циклично перебираются найденные записи журнала пока их время свежЕе, чем время последнего сообщения, отправленного в Telegram.
3. В теле цикла каждая запись прогоняется через функцию FindMacAddr, которая по необходимости прилепляет к ней комментарий.
4. В теле цикла также производится дополнительная фильтрация записей, чтобы рассылать меньше спама.
5. По окончании работы цикла будет сгенерировано сообщение, состоящее из нескольких выбранных и прокомментированных записей журнала, если таковые имелись.
6. Если есть что отправлять, тогда формируется строка для отправки в Telegram с попутным задействованием функции SpaceToCode и собственно производится отправка. Плюс к этому в $lastTimeLog запоминается время последней отправки.
7. Вся работа скрипта со временем производится через функцию EpochTime от Jotne, исключающую проблемы при начале новых суток.
8. В процессе работы скрипт выводит информацию для облегчения понимания происходящего.
Примерно так...
Не претендую на совершенство кода. Допускаю ошибки и недоработки. Путаю педали. Все замечания и конструктивная критика приветствуются.