@@ -5,13 +5,14 @@ import (
55 "encoding/json"
66 "fmt"
77 "html/template"
8- "io"
98 "log"
109 "net"
1110 "net/http"
1211 "net/url"
1312 "os"
1413 "os/exec"
14+ "runtime"
15+ "sort"
1516 "strings"
1617 "time"
1718
@@ -114,8 +115,8 @@ const (
114115</div>
115116<div class="footer">
116117 <p>Last updated: {{.last_updated}}</p>
117- <p>Powered by <a href="https://github.com/annihilatorrrr/gotinystatus">GoTinyStatus</a></p>
118118 <p><a href="history">View Status History</a></p>
119+ <p>Powered by <a href="https://github.com/annihilatorrrr/gotinystatus">GoTinyStatus</a></p>
119120</div>
120121</body>
121122</html>`
@@ -198,8 +199,8 @@ const (
198199</div>
199200<div class="footer">
200201 <p>Last updated: {{.last_updated}}</p>
201- <p>Powered by <a href="https://github.com/annihilatorrrr/gotinystatus">GoTinyStatus</a></p>
202202 <p><a href="/">Back to Current Status</a></p>
203+ <p>Powered by <a href="https://github.com/annihilatorrrr/gotinystatus">GoTinyStatus</a></p>
203204</div>
204205</body>
205206</html>`
@@ -208,7 +209,7 @@ const (
208209)
209210
210211var (
211- checkInterval = getEnvInt ("CHECK_INTERVAL" , 30 )
212+ checkInterval = getEnvInt ("CHECK_INTERVAL" , 60 )
212213 maxHistoryEntries = getEnvInt ("MAX_HISTORY_ENTRIES" , 10 )
213214 checksFile = getEnv ("CHECKS_FILE" , "checks.yaml" )
214215 incidentsFile = getEnv ("INCIDENTS_FILE" , "incidents.html" )
@@ -239,9 +240,7 @@ func checkHTTP(url string, expectedCode int) bool {
239240 if err != nil {
240241 return false
241242 }
242- defer func (Body io.ReadCloser ) {
243- _ = Body .Close ()
244- }(resp .Body )
243+ _ = resp .Body .Close ()
245244 return resp .StatusCode == expectedCode
246245}
247246
@@ -321,49 +320,16 @@ func updateHistory(results []map[string]interface{}) {
321320 history [name ] = []HistoryEntry {}
322321 }
323322 history [name ] = append (history [name ], HistoryEntry {currentTime , result ["status" ].(bool )})
323+ sort .Slice (history [name ], func (i , j int ) bool {
324+ timeI , _ := time .Parse (time .RFC3339 , history [name ][i ].Timestamp )
325+ timeJ , _ := time .Parse (time .RFC3339 , history [name ][j ].Timestamp )
326+ return timeI .After (timeJ )
327+ })
324328 if len (history [name ]) > maxHistoryEntries {
325- history [name ] = history [name ][len ( history [ name ]) - maxHistoryEntries : ]
329+ history [name ] = history [name ][: maxHistoryEntries ]
326330 }
327331 }
328332 saveHistory (history )
329- if token != "" {
330- for key , data := range loadHistory () {
331- if total := len (data ); total >= 2 {
332- if data [1 ].Status == data [0 ].Status {
333- continue
334- }
335- okis := "Down!\n From last"
336- if data [1 ].Status {
337- okis = "Up!\n From last"
338- }
339- go func (thestr string ) {
340- resp , err := http .Get (fmt .Sprintf ("https://api.telegram.org/bot%s/sendMessage?chat_id=%s&parse_mode=html&text=%s" , token , chatid , url .QueryEscape (thestr )))
341- if err != nil {
342- log .Println (err .Error ())
343- return
344- }
345- defer func (Body io.ReadCloser ) {
346- _ = Body .Close ()
347- }(resp .Body )
348- }(fmt .Sprintf ("<b>%s is now %s %ds!</b>" , key , okis , checkInterval ))
349- } else {
350- okis := "Down!\n From last"
351- if data [0 ].Status {
352- okis = "Up!\n From last"
353- }
354- go func (thestr string ) {
355- resp , err := http .Get (fmt .Sprintf ("https://api.telegram.org/bot%s/sendMessage?chat_id=%s&parse_mode=html&text=%s" , token , chatid , url .QueryEscape (thestr )))
356- if err != nil {
357- log .Println (err .Error ())
358- return
359- }
360- defer func (Body io.ReadCloser ) {
361- _ = Body .Close ()
362- }(resp .Body )
363- }(fmt .Sprintf ("<b>%s is now %s %ds!</b>" , key , okis , checkInterval ))
364- }
365- }
366- }
367333}
368334
369335func renderTemplate (data map [string ]interface {}) string {
@@ -437,6 +403,40 @@ func monitorServices() {
437403 }
438404 generateHistoryPage ()
439405 log .Println ("Status pages updated!" )
406+ if token != "" && chatid != "" {
407+ log .Println ("Notifying on telegram ..." )
408+ for key , data := range loadHistory () {
409+ if total := len (data ); total >= 2 {
410+ latestdata := data [:2 ]
411+ if latestdata [0 ].Status == latestdata [1 ].Status {
412+ continue
413+ }
414+ lastst := latestdata [1 ].Status
415+ newinterval := checkInterval
416+ for x , y := range data {
417+ if x > 1 {
418+ if y .Status == lastst {
419+ newinterval += 60
420+ } else {
421+ break
422+ }
423+ }
424+ }
425+ tosend := fmt .Sprintf ("<b>✅ %s is now Up!</b>\n Seen Down from last %ds!" , key , newinterval )
426+ if ! latestdata [0 ].Status {
427+ tosend = fmt .Sprintf ("<b> 🛑 %s is now Down!</b>\n Was seen Up from last %ds!" , key , newinterval )
428+ }
429+ _ = checkHTTP (fmt .Sprintf ("https://api.telegram.org/bot%s/sendMessage?chat_id=%s&parse_mode=html&text=%s" , token , chatid , url .QueryEscape (tosend )), 200 )
430+ } else {
431+ tosend := fmt .Sprintf ("<b> 🛑 %s is now Down!</b>" , key )
432+ if data [0 ].Status {
433+ tosend = fmt .Sprintf ("<b>✅ %s is now Up!</b>" , key )
434+ }
435+ _ = checkHTTP (fmt .Sprintf ("https://api.telegram.org/bot%s/sendMessage?chat_id=%s&parse_mode=html&text=%s" , token , chatid , url .QueryEscape (tosend )), 200 )
436+ }
437+ }
438+ log .Println ("Notified on telegram!" )
439+ }
440440 time .Sleep (time .Duration (checkInterval ) * time .Second )
441441 }
442442}
@@ -449,6 +449,47 @@ func serveFile(w http.ResponseWriter, r *http.Request, filePath string) {
449449 http .ServeFile (w , r , filePath )
450450}
451451
452+ func handleHome (w http.ResponseWriter , r * http.Request ) {
453+ if r .Method != http .MethodGet {
454+ http .Error (w , "Method Not Allowed!" , http .StatusMethodNotAllowed )
455+ return
456+ }
457+ _ , _ = fmt .Fprintf (w , `
458+ <!DOCTYPE html>
459+ <html lang="en">
460+ <head>
461+ <meta charset="UTF-8">
462+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
463+ <title>Service Status</title>
464+ <style>
465+ body {
466+ background-color: #121212;
467+ color: #e0e0e0;
468+ font-family: Arial, sans-serif;
469+ line-height: 1.6;
470+ margin: 0;
471+ padding: 20px;
472+ }
473+ h1 {
474+ color: #bb86fc;
475+ }
476+ pre {
477+ background-color: #1e1e1e;
478+ padding: 10px;
479+ border-radius: 5px;
480+ overflow-x: auto;
481+ }
482+ </style>
483+ </head>
484+ <body>
485+ <h1>I'm alive!</h1>
486+ <p>Go Version: %s</p>
487+ <p>Go Routines: %d</p>
488+ <p>Source Code: <a href="https://github.com/annihilatorrrr/gotinystatus" style="color: #bb86fc;">Gotinystatus</a></p>
489+ </body>
490+ </html>` , runtime .Version (), runtime .NumGoroutine ())
491+ }
492+
452493func main () {
453494 log .Println ("Monitoring services ..." )
454495 if port != "" {
@@ -460,18 +501,26 @@ func main() {
460501 http .NotFound (w , r )
461502 }
462503 })
504+ http .HandleFunc ("/status" , func (w http.ResponseWriter , r * http.Request ) {
505+ if strings .HasPrefix (r .URL .Path , "/status" ) {
506+ handleHome (w , r )
507+ } else {
508+ http .NotFound (w , r )
509+ }
510+ })
463511 http .HandleFunc ("/history" , func (w http.ResponseWriter , r * http.Request ) {
464- if r .URL .Path == "/history" {
512+ if strings . HasPrefix ( r .URL .Path , "/history" ) {
465513 serveFile (w , r , "./" + historyfile )
466514 } else {
467515 http .NotFound (w , r )
468516 }
469517 })
470518 log .Println ("Server started!" )
471519 if err := http .ListenAndServe (":" + port , nil ); err != nil {
472- log .Fatal (err )
520+ log .Println (err . Error () )
473521 }
474522 } else {
475523 monitorServices ()
476524 }
525+ log .Println ("Bye!" )
477526}
0 commit comments