Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
########## CONFIG ########## set kuma_webhook_port 8787 set kuma_webhook_path "/kuma" set kuma_webhook_chan "#status" # Optional shared secret (must match X-Kuma-Secret header in Kuma) set kuma_webhook_secret "yourSecretHere" ########## INTERNAL STATE – DO NOT EDIT ########## array set kuma_state {} array set kuma_method {} array set kuma_path {} array set kuma_len {} array set kuma_body {} array set kuma_secret_hdr {} ########## COLORS ########## # IRC color codes set kuma_color_reset "\017" set kuma_color_red "\00304" set kuma_color_green "\00303" ########## LISTENER ########## if {![info exists kuma_webhook_initialized]} { set kuma_webhook_initialized 1 listen $kuma_webhook_port script kuma:accept putlog "Uptime Kuma webhook: listening on port $kuma_webhook_port, path $kuma_webhook_path" } proc kuma:accept {idx} { global kuma_state kuma_len kuma_body kuma_secret_hdr set kuma_state($idx) "request" set kuma_len($idx) 0 set kuma_body($idx) "" set kuma_secret_hdr($idx) "" control $idx kuma:control return 0 } proc kuma:control {idx text} { global kuma_state kuma_method kuma_path kuma_len kuma_body kuma_secret_hdr if {![info exists kuma_state($idx)]} { set kuma_state($idx) "request" } switch -- $kuma_state($idx) { request { if {![regexp {^([A-Z]+) ([^ ]+) HTTP/} $text -> method path]} { kuma:respond $idx 400 "Bad Request" return 0 } set kuma_method($idx) $method set kuma_path($idx) $path set kuma_state($idx) "headers" } headers { if {$text eq ""} { set kuma_state($idx) "body" if {$kuma_len($idx) == 0} { kuma:handle $idx } return 0 } if {[regexp -nocase {^Content-Length:\s*([0-9]+)} $text -> len]} { set kuma_len($idx) $len } elseif {[regexp -nocase {^X-Kuma-Secret:\s*(.+)} $text -> sec]} { set kuma_secret_hdr($idx) [string trim $sec] } } body { append kuma_body($idx) $text if {$kuma_len($idx) == 0 || [string length $kuma_body($idx)] >= $kuma_len($idx)} { kuma:handle $idx } } } return 0 } ########## REQUEST HANDLING ########## proc kuma:handle {idx} { global kuma_method kuma_path kuma_body kuma_secret_hdr global kuma_webhook_path kuma_webhook_secret kuma_webhook_chan global kuma_color_reset kuma_color_red kuma_color_green if {$kuma_method($idx) ne "POST"} { kuma:respond $idx 405 "Method Not Allowed" return } set fullPath $kuma_path($idx) if {[regexp {^([^?]+)} $fullPath -> cleanPath]} { set pathOnly $cleanPath } else { set pathOnly $fullPath } if {$pathOnly ne $kuma_webhook_path} { kuma:respond $idx 404 "Not Found" return } if {$kuma_webhook_secret ne ""} { if {![info exists kuma_secret_hdr($idx)] || $kuma_secret_hdr($idx) ne $kuma_webhook_secret} { kuma:respond $idx 403 "Forbidden" return } } set body "" if {[info exists kuma_body($idx)]} { set body [string trim $kuma_body($idx)] } # --- Simple JSON-ish parsing for: {"monitor":"...","status":"...","reason":"..."} --- set monitor "" set status "" set reason "" if {[regexp {"monitor"\s*:\s*"([^"]*)"} $body -> m]} { set monitor [string trim $m] } if {[regexp {"status"\s*:\s*"([^"]*)"} $body -> s]} { set status [string toupper [string trim $s]] } if {[regexp {"reason"\s*:\s*"([^"]*)"} $body -> r]} { # Unescape basic things set reason [string map {\\n " " \\r " " \\" "\""} $r] set reason [string trim $reason] } if {$monitor eq ""} { set monitor "Unknown Monitor" } if {$reason eq ""} { set reason "No reason provided" } # Build colored status text if {$status eq "UP"} { set status_colored "${kuma_color_green}UP${kuma_color_reset}" } elseif {$status eq "DOWN"} { set status_colored "${kuma_color_red}DOWN${kuma_color_reset}" } else { # Fallback if status is weird set status_colored $status } # Line 1: "
is (coloured)UP/DOWN" set line1 "$monitor is $status_colored" # Line 2: # Down: "
Failed -
" # Up: "
Up -
" if {$status eq "DOWN"} { set line2 "$monitor Failed - $reason" } elseif {$status eq "UP"} { set line2 "$monitor Up - $reason" } else { set line2 "$monitor - $reason" } if {$kuma_webhook_chan ne ""} { putserv "PRIVMSG $kuma_webhook_chan :$line1" putserv "PRIVMSG $kuma_webhook_chan :$line2" } kuma:respond $idx 200 "OK" } ########## RESPONSE & CLEANUP ########## proc kuma:respond {idx code text} { set body $text set len [string length $body] putdcc $idx "HTTP/1.1 $code $text" putdcc $idx "Content-Type: text/plain" putdcc $idx "Content-Length: $len" putdcc $idx "" putdcc $idx $body kuma:cleanup $idx } proc kuma:cleanup {idx} { global kuma_state kuma_method kuma_path kuma_len kuma_body kuma_secret_hdr catch {unset kuma_state($idx)} catch {unset kuma_method($idx)} catch {unset kuma_path($idx)} catch {unset kuma_len($idx)} catch {unset kuma_body($idx)} catch {unset kuma_secret_hdr($idx)} catch {killdcc $idx} }
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)