github.com/wtfutil/wtf@v0.43.0/modules/uptimerobot/widget.go (about) 1 package uptimerobot 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "io" 8 "net/http" 9 "net/url" 10 "strings" 11 12 "github.com/rivo/tview" 13 "github.com/wtfutil/wtf/view" 14 ) 15 16 type Widget struct { 17 view.ScrollableWidget 18 19 monitors []Monitor 20 settings *Settings 21 err error 22 } 23 24 func NewWidget(tviewApp *tview.Application, redrawChan chan bool, pages *tview.Pages, settings *Settings) *Widget { 25 widget := &Widget{ 26 ScrollableWidget: view.NewScrollableWidget(tviewApp, redrawChan, pages, settings.Common), 27 28 settings: settings, 29 } 30 31 widget.SetRenderFunction(widget.Render) 32 widget.initializeKeyboardControls() 33 34 return widget 35 } 36 37 /* -------------------- Exported Functions -------------------- */ 38 39 func (widget *Widget) Refresh() { 40 if widget.Disabled() { 41 return 42 } 43 44 monitors, err := widget.getMonitors() 45 46 if widget.settings.offlineFirst { 47 var tmp Monitor 48 var next int 49 for i := 0; i < len(monitors); i++ { 50 if monitors[i].State != 2 { 51 tmp = monitors[i] 52 for j := i; j > next; j-- { 53 monitors[j] = monitors[j-1] 54 } 55 monitors[next] = tmp 56 next++ 57 } 58 } 59 } 60 61 widget.monitors = monitors 62 widget.err = err 63 widget.SetItemCount(len(monitors)) 64 65 widget.Render() 66 } 67 68 // Render sets up the widget data for redrawing to the screen 69 func (widget *Widget) Render() { 70 widget.Redraw(widget.content) 71 } 72 73 /* -------------------- Unexported Functions -------------------- */ 74 75 func (widget *Widget) content() (string, string, bool) { 76 numUp := 0 77 for _, monitor := range widget.monitors { 78 if monitor.State == 2 { 79 numUp++ 80 } 81 } 82 83 title := fmt.Sprintf("%s (%d/%d)", widget.CommonSettings().Title, numUp, len(widget.monitors)) 84 85 if widget.err != nil { 86 return title, widget.err.Error(), true 87 } 88 89 if widget.monitors == nil { 90 return title, "No monitors to display", false 91 } 92 93 str := widget.contentFrom(widget.monitors) 94 95 return title, str, false 96 } 97 98 func (widget *Widget) contentFrom(monitors []Monitor) string { 99 var str string 100 101 for _, monitor := range monitors { 102 prefix := "" 103 104 switch monitor.State { 105 case 2: 106 prefix += "[green] + " 107 case 8: 108 case 9: 109 prefix += "[red] - " 110 default: 111 prefix += "[yellow] ~ " 112 } 113 114 str += fmt.Sprintf(`%s%s [gray](%s)[white] 115 `, 116 prefix, 117 monitor.Name, 118 formatUptimes(monitor.Uptime), 119 ) 120 } 121 122 return str 123 } 124 125 func formatUptimes(str string) string { 126 splits := strings.Split(str, "-") 127 str = "" 128 for i, s := range splits { 129 if i != 0 { 130 str += "|" 131 } 132 s = s[:5] 133 s = strings.TrimRight(s, "0") 134 s = strings.TrimRight(s, ".") + "%" 135 str += s 136 } 137 return str 138 } 139 140 type Monitor struct { 141 Name string `json:"friendly_name"` 142 // Monitor state, see: https://uptimerobot.com/api/#parameters 143 State int8 `json:"status"` 144 // Uptime ratio, preformatted, e.g.: 100.000-97.233-96.975 145 Uptime string `json:"custom_uptime_ratio"` 146 } 147 148 func (widget *Widget) getMonitors() ([]Monitor, error) { 149 // See: https://uptimerobot.com/api/#getMonitorsWrap 150 resp, errh := http.PostForm("https://api.uptimerobot.com/v2/getMonitors", 151 url.Values{ 152 "api_key": {widget.settings.apiKey}, 153 "format": {"json"}, 154 "custom_uptime_ratios": {widget.settings.uptimePeriods}, 155 }, 156 ) 157 158 if errh != nil { 159 return nil, errh 160 } 161 defer func() { _ = resp.Body.Close() }() 162 163 body, _ := io.ReadAll(resp.Body) 164 165 // First pass to read the status 166 c := make(map[string]json.RawMessage) 167 errj1 := json.Unmarshal(body, &c) 168 169 if errj1 != nil { 170 return nil, errj1 171 } 172 173 if string(c["stat"]) != `"ok"` { 174 return nil, errors.New(string(body)) 175 } 176 177 // Second pass to get the actual info 178 var monitors []Monitor 179 errj2 := json.Unmarshal(c["monitors"], &monitors) 180 181 if errj2 != nil { 182 return nil, errj2 183 } 184 185 return monitors, nil 186 }