From b8ef8d13038ff79cb5d96e5af0f7851b6a3a2e15 Mon Sep 17 00:00:00 2001 From: vados-dev <192440777+vados-dev@users.noreply.github.com> Date: Fri, 1 May 2026 00:05:03 +0300 Subject: [PATCH] Autocommit in repo: ros.vados.ru, generated by owner: root, in 00:05:03 01.05.2026. --- html/AM-GlobalFunc.rsc | 4 +- html/mod/AM-TG-Notifications.rsc.diff | 150 ++++++++++++++++ html/mod/notification-telegram.rsc | 250 ++++++++++++++++++++++++++ 3 files changed, 402 insertions(+), 2 deletions(-) create mode 100644 html/mod/AM-TG-Notifications.rsc.diff create mode 100644 html/mod/notification-telegram.rsc diff --git a/html/AM-GlobalFunc.rsc b/html/AM-GlobalFunc.rsc index 5e1a4c267..94abee9b1 100644 --- a/html/AM-GlobalFunc.rsc +++ b/html/AM-GlobalFunc.rsc @@ -17,9 +17,9 @@ :global GlobalFuncReady false; # Git commit id & info, expected configuration version -:global CommitId "main/308/f5b1bfb4"; +:global CommitId "main/313/19cfdc2a"; :global CommitTAG "unknown"; -:global CommitInfo "Autocommit in repo: ros.vados.ru, generated by owner: root, in 21:50:02 30.04.2026."; +:global CommitInfo "Autocommit in repo: ros.vados.ru, generated by owner: root, in 00:05:03 01.05.2026."; # The variables are received right here. :global GlobalConfVersion 138; diff --git a/html/mod/AM-TG-Notifications.rsc.diff b/html/mod/AM-TG-Notifications.rsc.diff new file mode 100644 index 000000000..2e31baf10 --- /dev/null +++ b/html/mod/AM-TG-Notifications.rsc.diff @@ -0,0 +1,150 @@ +1,5c1,4 +< #!rsc by Vados +< # RouterOS script: mod/AM-TG-Notifications +< # Script comment: Script send Notifications in Telegram +< # Copyright (c) 2007-2026 Vados +< # +--- +> #!rsc by RouterOS +> # RouterOS script: mod/notification-telegram +> # Copyright (c) 2013-2026 Christian Hesse +> # https://rsc.eworm.de/COPYING.md +9,14c8,10 +< :local ExitOK false; +< :onerror Err { +< :global GlobalConfReady; :global GlobalFuncReady; +< :retry { :if ($GlobalConfReady != true || $GlobalFuncReady != true) \ +< do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50; +< :local ScriptName [ :jobname ]; +--- +> # +> # send notifications via Telegram +> # https://rsc.eworm.de/doc/mod/notification-telegram.md +26a23 +> +30,34c27,32 +< +< #:if ([ $IsFullyConnected ] = false) do={ +< # $LogPrint debug $0 ("System is not fully connected, not flushing."); +< # :return false; +< #} +--- +> +> :if ([ $IsFullyConnected ] = false) do={ +> $LogPrint debug $0 ("System is not fully connected, not flushing."); +> :return false; +> } +> +41a40 +> +44a44 +> +58a59 +> +63,64c64,67 +< } do={:global ExitOnError; $ExitOnError $0 $Err} +< } +--- +> } do={ +> :global ExitOnError; $ExitOnError $0 $Err; +> } } +> +68c71,72 +< # :global CertificateAvailable; +--- +> +> :global CertificateAvailable; +70,73c74,79 +< # :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" "fetch" ] = false) do={ +< # $LogPrint warning $0 ("Downloading required certificate failed."); +< # :return false; +< # } +--- +> +> :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" "fetch" ] = false) do={ +> $LogPrint warning $0 ("Downloading required certificate failed."); +> :return false; +> } +> +82a89 +> +84a92 +> +88a97 +> +94,95c103,106 +< } do={:global ExitOnError; $ExitOnError $0 $Err} +< } +--- +> } do={ +> :global ExitOnError; $ExitOnError $0 $Err; +> } } +> +98a110 +> +108a121 +> +116a130 +> +120a135 +> +122a138 +> +133c149,153 +< :if ($Mode = "body") do={:return ("```\n" . $Text . "\n```")} +--- +> +> :if ($Mode = "body") do={ +> :return ("```\n" . $Text . "\n```"); +> } +> +135a156 +> +142,143c163,171 +< :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={:return false} +< :if ([ :typeof $TelegramMessageIDs ] = "nothing") do={:set TelegramMessageIDs ({})} +--- +> +> :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ +> :return false; +> } +> +> :if ([ :typeof $TelegramMessageIDs ] = "nothing") do={ +> :set TelegramMessageIDs ({}); +> } +> +154c182,184 +< } else={:set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ])} +--- +> } else={ +> :set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]); +> } +164a195 +> +179c210,213 +< :if ([ :typeof $TelegramQueue ] = "nothing") do={:set TelegramQueue ({})} +--- +> +> :if ([ :typeof $TelegramQueue ] = "nothing") do={ +> :set TelegramQueue ({}); +> } +190a225 +> +193a229 +> +196a233 +> +199a237 +> +201,202c239,242 +< } do={:global ExitOnError; $ExitOnError $0 $Err} +< } +--- +> } do={ +> :global ExitOnError; $ExitOnError $0 $Err; +> } } +> +205a246 +> +206a248 +> diff --git a/html/mod/notification-telegram.rsc b/html/mod/notification-telegram.rsc new file mode 100644 index 000000000..ce9dc3f12 --- /dev/null +++ b/html/mod/notification-telegram.rsc @@ -0,0 +1,250 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-telegram +# Copyright (c) 2013-2026 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# requires RouterOS, version=7.19 +# requires device-mode, fetch, scheduler +# +# send notifications via Telegram +# https://rsc.eworm.de/doc/mod/notification-telegram.md + +:global FlushTelegramQueue; +:global GetTelegramChatId; +:global NotificationFunctions; +:global PurgeTelegramQueue; +:global SendTelegram; +:global SendTelegram2; + +# flush telegram queue +:set FlushTelegramQueue do={ :onerror Err { + :global TelegramQueue; + :global TelegramMessageIDs; + + :global CertificateAvailable; + :global IsFullyConnected; + :global LogPrint; + + :if ([ $IsFullyConnected ] = false) do={ + $LogPrint debug $0 ("System is not fully connected, not flushing."); + :return false; + } + + :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" "fetch" ] = false) do={ + $LogPrint warning $0 ("Downloading required certificate failed."); + :return false; + } + + :local AllDone true; + :local QueueLen [ :len $TelegramQueue ]; + + :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrint warning $0 ("Flushing Telegram messages from scheduler, but queue is empty."); + } + + :foreach Id,Message in=$TelegramQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :onerror Err { + :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ + ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ + http-data=($Message->"http-data") as-value ]->"data"); + :set ($TelegramQueue->$Id); + :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; + } do={ + $LogPrint debug $0 ("Sending queued Telegram message failed: " . $Err); + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ + /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; + :set TelegramQueue; + } +} do={ + :global ExitOnError; $ExitOnError $0 $Err; +} } + +# get the chat id +:set GetTelegramChatId do={ :onerror Err { + :global TelegramTokenId; + + :global CertificateAvailable; + :global LogPrint; + + :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" "fetch" ] = false) do={ + $LogPrint warning $0 ("Downloading required certificate failed."); + :return false; + } + + :local Data; + :onerror Err { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=0" . \ + "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + } do={ + $LogPrint warning $0 ("Fetching data failed: " . $Err); + :return false; + } + + :local JSON [ :deserialize from=json value=$Data ]; + :local Count [ :len ($JSON->"result") ]; + + :if ($Count = 0) do={ + $LogPrint info $0 ("No message received."); + :return false; + } + + :local Message ($JSON->"result"->($Count - 1)->"message"); + $LogPrint info $0 ("The chat id is: " . ($Message->"chat"->"id")); + :if (($Message->"is_topic_message") = true) do={ + $LogPrint info $0 ("The thread id is: " . ($Message->"message_thread_id")); + } +} do={ + :global ExitOnError; $ExitOnError $0 $Err; +} } + +# send notification via telegram - expects one array argument +:set ($NotificationFunctions->"telegram") do={ + :local Notification $1; + + :global Identity; + :global IdentityExtra; + :global TelegramChatId; + :global TelegramChatIdOverride; + :global TelegramMessageIDs; + :global TelegramQueue; + :global TelegramThreadId; + :global TelegramThreadIdOverride; + :global TelegramTokenId; + :global TelegramTokenIdOverride; + + :global CertificateAvailable; + :global CharacterReplace; + :global EitherOr; + :global IfThenElse; + :global LogPrint; + :global ProtocolStrip; + :global SymbolForNotification; + :global UrlEncode; + + :local EscapeMD do={ + :local Text [ :tostr $1 ]; + :local Mode [ :tostr $2 ]; + :local Excl [ :tostr $3 ]; + + :global CharacterReplace; + :global IfThenElse; + + :local Chars { + "body"={ "\\"; "`" }; + "plain"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; + "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; + } + :foreach Char in=($Chars->$Mode) do={ + :if ([ :typeof [ :find $Excl $Char ] ] = "nil") do={ + :set Text [ $CharacterReplace $Text $Char ("\\" . $Char) ]; + } + } + + :if ($Mode = "body") do={ + :return ("```\n" . $Text . "\n```"); + } + + :return $Text; + } + + :local ChatId [ $EitherOr ($Notification->"chatid") \ + [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ]; + :local ThreadId [ $EitherOr ($Notification->"threadid") \ + [ $EitherOr ($TelegramThreadIdOverride->($Notification->"origin")) \ + [ $IfThenElse ([ :len ($TelegramChatIdOverride->($Notification->"origin")) ] = 0) $TelegramThreadId ] ] ]; + :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; + + :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ + :return false; + } + + :if ([ :typeof $TelegramMessageIDs ] = "nothing") do={ + :set TelegramMessageIDs ({}); + } + + :local Truncated false; + :local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject")) "plain" ] . "__*\n\n"); + :local LenSubject [ :len $Text ]; + :local LenMessage [ :len ($Notification->"message") ]; + :local LenLink ([ :len ($Notification->"link") ] * 2); + :local LenSum ($LenSubject + $LenMessage + $LenLink); + :if ($LenSum > 3968) do={ + :set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]); + :set Truncated true; + } else={ + :set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]); + } + :if ($LenLink > 0) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . \ + "[" . [ $EscapeMD [ $ProtocolStrip ($Notification->"link") ] "plain" ] . "]" . \ + "(" . [ $EscapeMD ($Notification->"link") "plain" ] . ")"); + } + :if ($Truncated = true) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ + [ $EscapeMD ("The message was too long and has been truncated, cut off _" . \ + (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%_!") "plain" "_" ]); + } + + :local HTTPData ("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ + "&reply_to_message_id=" . ($Notification->"replyto") . "&message_thread_id=" . $ThreadId . \ + "&disable_web_page_preview=true&parse_mode=MarkdownV2"); + :onerror Err { + :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" "fetch" ] = false) do={ + $LogPrint warning $0 ("Downloading required certificate failed."); + :error false; + } + :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ + ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ + http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); + :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; + } do={ + $LogPrint info $0 ("Failed sending Telegram notification: " . $Err . " - Queuing..."); + + :if ([ :typeof $TelegramQueue ] = "nothing") do={ + :set TelegramQueue ({}); + } + :set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \ + [ $EscapeMD ("This message was queued since _" . [ /system/clock/get date ] . \ + " " . [ /system/clock/get time ] . "_ and may be obsolete.") "plain" "_" ]); + :set ($TelegramQueue->[ :len $TelegramQueue ]) { tokenid=$TokenId; + http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) }; + :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={ + /system/scheduler/add name="_FlushTelegramQueue" interval=1m start-time=startup \ + on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); + } + } +} + +# purge the Telegram queue +:set PurgeTelegramQueue do={ + :global TelegramQueue; + + /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; + :set TelegramQueue; +} + +# send notification via telegram - expects at least two string arguments +:set SendTelegram do={ :onerror Err { + :global SendTelegram2; + + $SendTelegram2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); +} do={ + :global ExitOnError; $ExitOnError $0 $Err; +} } + +# send notification via telegram - expects one array argument +:set SendTelegram2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; +} -- 2.52.0