]> Git [git.vados.ru] :: Repos - Mikrotiks/ros.vados.ru.git/commitdiff
Autocommit in repo: ros.vados.ru, generated by owner: root, in 00:05:03 01.05.2026.
authorvados-dev <192440777+vados-dev@users.noreply.github.com>
Thu, 30 Apr 2026 21:05:03 +0000 (00:05 +0300)
committervados-dev <192440777+vados-dev@users.noreply.github.com>
Thu, 30 Apr 2026 21:05:03 +0000 (00:05 +0300)
html/AM-GlobalFunc.rsc
html/mod/AM-TG-Notifications.rsc.diff [new file with mode: 0644]
html/mod/notification-telegram.rsc [new file with mode: 0644]

index 5e1a4c267b21067969f2cda487feb5fd276a764b..94abee9b14f25bf85b3ad411067c77f4d6c8f19f 100644 (file)
@@ -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 (file)
index 0000000..2e31baf
--- /dev/null
@@ -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 <vados@vados.ru>
+< #
+---
+> #!rsc by RouterOS
+> # RouterOS script: mod/notification-telegram
+> # Copyright (c) 2013-2026 Christian Hesse <mail@eworm.de>
+> # 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 (file)
index 0000000..ce9dc3f
--- /dev/null
@@ -0,0 +1,250 @@
+#!rsc by RouterOS
+# RouterOS script: mod/notification-telegram
+# Copyright (c) 2013-2026 Christian Hesse <mail@eworm.de>
+# 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;
+}