github.com/wtfutil/wtf@v0.43.0/modules/pihole/view.go (about) 1 package pihole 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "net/http" 8 "sort" 9 "strconv" 10 "strings" 11 12 "github.com/olekukonko/tablewriter" 13 ) 14 15 func getSummaryView(c http.Client, settings *Settings) string { 16 var err error 17 18 var s Status 19 20 s, err = getStatus(c, settings.apiUrl) 21 if err != nil { 22 return err.Error() 23 } 24 25 var sb strings.Builder 26 27 buf := new(bytes.Buffer) 28 29 switch strings.ToLower(s.Status) { 30 case "disabled": 31 sb.WriteString(" [white]Status [red]DISABLED\n") 32 case "enabled": 33 sb.WriteString(" [white]Status [green]ENABLED\n") 34 default: 35 sb.WriteString(" [white]Status [yellow]UNKNOWN\n") 36 } 37 38 summaryTable := createTable([]string{}, buf) 39 summaryTable.Append([]string{"Domain blocklist", s.DomainsBeingBlocked, "Queries today", s.DNSQueriesToday}) 40 summaryTable.Append([]string{"Ads blocked today", fmt.Sprintf("%s (%s%%)", s.AdsBlockedToday, s.AdsPercentageToday), "Cached queries", s.QueriesCached}) 41 summaryTable.Append([]string{"Blocklist Age", fmt.Sprintf("%dd %dh %dm", s.GravityLastUpdated.Relative.Days, 42 s.GravityLastUpdated.Relative.Hours, s.GravityLastUpdated.Relative.Minutes), "Forwarded queries", s.QueriesForwarded}) 43 summaryTable.Render() 44 45 sb.WriteString(buf.String()) 46 47 return sb.String() 48 } 49 50 func getTopItemsView(c http.Client, settings *Settings) string { 51 var err error 52 53 var ti TopItems 54 55 ti, err = getTopItems(c, settings) 56 if err != nil { 57 return err.Error() 58 } 59 60 buf := new(bytes.Buffer) 61 62 var sb strings.Builder 63 64 tiTable := createTable([]string{"Top Queries", "", "Top Ads", ""}, buf) 65 66 largest := len(ti.TopAds) 67 if len(ti.TopQueries) > largest { 68 largest = len(ti.TopQueries) 69 } 70 71 sortedTiQueries := sortMapByIntVal(ti.TopQueries) 72 73 sortedTiAds := sortMapByIntVal(ti.TopAds) 74 75 for x := 0; x < largest; x++ { 76 tiQVal := []string{"", ""} 77 if len(sortedTiQueries) > x { 78 tiQVal = []string{shorten(sortedTiQueries[x][0], settings.maxDomainWidth), sortedTiQueries[x][1]} 79 } 80 81 tiAVal := []string{"", ""} 82 83 if len(sortedTiAds) > x { 84 tiAVal = []string{shorten(sortedTiAds[x][0], settings.maxDomainWidth), sortedTiAds[x][1]} 85 } 86 87 tiTable.Append([]string{tiQVal[0], tiQVal[1], tiAVal[0], tiAVal[1]}) 88 } 89 90 tiTable.Render() 91 sb.WriteString(buf.String()) 92 93 return sb.String() 94 } 95 96 func getTopClientsView(c http.Client, settings *Settings) string { 97 tc, err := getTopClients(c, settings) 98 if err != nil { 99 return err.Error() 100 } 101 102 var tq QueryTypes 103 104 tq, err = getQueryTypes(c, settings) 105 if err != nil { 106 return err.Error() 107 } 108 109 buf := new(bytes.Buffer) 110 111 tcTable := createTable([]string{"Top Clients", "", "Top Query Types", ""}, buf) 112 113 sortedTcQueries := sortMapByIntVal(tc.TopSources) 114 115 sortedTopQT := sortMapByFloatVal(tq.QueryTypes) 116 117 largest := len(tc.TopSources) 118 119 if len(tq.QueryTypes) > largest { 120 largest = len(tq.QueryTypes) 121 } 122 123 if settings.showTopClients < largest { 124 largest = settings.showTopClients 125 } 126 127 for x := 0; x < largest; x++ { 128 tcVal := []string{"", ""} 129 130 if len(sortedTcQueries) > x { 131 tcVal = []string{sortedTcQueries[x][0], sortedTcQueries[x][1]} 132 } 133 134 tqtVal := []string{"", ""} 135 136 if len(sortedTopQT) > x && sortedTopQT[x][0] != "" { 137 tqtVal = []string{sortedTopQT[x][0], sortedTopQT[x][1] + "%"} 138 } 139 140 tcTable.Append([]string{tcVal[0], tcVal[1], tqtVal[0], tqtVal[1]}) 141 } 142 143 tcTable.Render() 144 145 var sb strings.Builder 146 147 sb.WriteString(buf.String()) 148 149 return sb.String() 150 } 151 152 func shorten(s string, limit int) string { 153 if len(s) > limit { 154 return s[:limit] + "..." 155 } 156 157 return s 158 } 159 160 func createTable(header []string, buf io.Writer) *tablewriter.Table { 161 table := tablewriter.NewWriter(buf) 162 163 if len(header) != 0 { 164 table.SetHeader(header) 165 table.SetHeaderLine(false) 166 table.SetHeaderAlignment(0) 167 } 168 169 table.SetAutoWrapText(false) 170 table.SetAutoFormatHeaders(true) 171 table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) 172 table.SetAlignment(tablewriter.ALIGN_LEFT) 173 table.SetBorder(true) 174 table.SetCenterSeparator("") 175 table.SetColumnSeparator("") 176 table.SetRowSeparator("") 177 table.SetTablePadding(" ") 178 table.SetNoWhiteSpace(false) 179 180 return table 181 } 182 183 func sortMapByIntVal(m map[string]int) (sorted [][]string) { 184 type kv struct { 185 Key string 186 Value int 187 } 188 189 ss := make([]kv, len(m)) 190 for k, v := range m { 191 ss = append(ss, kv{k, v}) 192 } 193 194 sort.Slice(ss, func(i, j int) bool { 195 return ss[i].Value > ss[j].Value 196 }) 197 198 for _, kv := range ss { 199 sorted = append(sorted, []string{kv.Key, strconv.Itoa(kv.Value)}) 200 } 201 202 return 203 } 204 205 func sortMapByFloatVal(m map[string]float32) (sorted [][]string) { 206 type kv struct { 207 Key string 208 Value float32 209 } 210 211 ss := make([]kv, len(m)) 212 213 for k, v := range m { 214 if k == "" || v == 0.00 { 215 continue 216 } 217 218 ss = append(ss, kv{k, v}) 219 } 220 221 sort.Slice(ss, func(i, j int) bool { 222 return ss[i].Value > ss[j].Value 223 }) 224 225 for _, kv := range ss { 226 sorted = append(sorted, []string{kv.Key, fmt.Sprintf("%.2f", kv.Value)}) 227 } 228 229 return 230 }