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  }