github.com/wtfutil/wtf@v0.43.0/modules/ipaddresses/ipapi/widget.go (about)

     1  package ipapi
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  	"strconv"
     9  	"strings"
    10  	"text/template"
    11  
    12  	"github.com/rivo/tview"
    13  	"github.com/wtfutil/wtf/utils"
    14  	"github.com/wtfutil/wtf/view"
    15  )
    16  
    17  // Widget widget struct
    18  type Widget struct {
    19  	view.TextWidget
    20  
    21  	result   string
    22  	settings *Settings
    23  }
    24  
    25  type ipinfo struct {
    26  	Query         string  `json:"query"`
    27  	ISP           string  `json:"isp"`
    28  	AS            string  `json:"as"`
    29  	ASName        string  `json:"asname"`
    30  	District      string  `json:"district"`
    31  	City          string  `json:"city"`
    32  	Region        string  `json:"region"`
    33  	RegionName    string  `json:"regionName"`
    34  	Country       string  `json:"country"`
    35  	CountryCode   string  `json:"countryCode"`
    36  	Continent     string  `json:"continent"`
    37  	ContinentCode string  `json:"continentCode"`
    38  	Latitude      float64 `json:"lat"`
    39  	Longitude     float64 `json:"lon"`
    40  	PostalCode    string  `json:"zip"`
    41  	Currency      string  `json:"currency"`
    42  	Organization  string  `json:"org"`
    43  	Timezone      string  `json:"timezone"`
    44  	ReverseDNS    string  `json:"reverse"`
    45  }
    46  
    47  var argLookup = map[string]string{
    48  	"ip":            "IP Address",
    49  	"isp":           "ISP",
    50  	"as":            "AS",
    51  	"asname":        "AS Name",
    52  	"district":      "District",
    53  	"city":          "City",
    54  	"region":        "Region",
    55  	"regionname":    "Region Name",
    56  	"country":       "Country",
    57  	"countrycode":   "Country Code",
    58  	"continent":     "Continent",
    59  	"continentcode": "Continent Code",
    60  	"coordinates":   "Coordinates",
    61  	"postalcode":    "Postal Code",
    62  	"currency":      "Currency",
    63  	"organization":  "Organization",
    64  	"timezone":      "Timezone",
    65  	"reversedns":    "Reverse DNS",
    66  }
    67  
    68  // NewWidget constructor
    69  func NewWidget(tviewApp *tview.Application, redrawChan chan bool, settings *Settings) *Widget {
    70  	widget := Widget{
    71  		TextWidget: view.NewTextWidget(tviewApp, redrawChan, nil, settings.Common),
    72  
    73  		settings: settings,
    74  	}
    75  
    76  	widget.View.SetWrap(false)
    77  
    78  	return &widget
    79  }
    80  
    81  // Refresh refresh the module
    82  func (widget *Widget) Refresh() {
    83  	widget.ipinfo()
    84  
    85  	widget.Redraw(func() (string, string, bool) { return widget.CommonSettings().Title, widget.result, false })
    86  }
    87  
    88  // this method reads the config and calls ipinfo for ip information
    89  func (widget *Widget) ipinfo() {
    90  	client := &http.Client{}
    91  	req, err := http.NewRequest("GET", "http://ip-api.com/json?fields=66846719", http.NoBody)
    92  	if err != nil {
    93  		widget.result = err.Error()
    94  		return
    95  	}
    96  	req.Header.Set("User-Agent", "curl")
    97  	response, err := client.Do(req)
    98  	if err != nil {
    99  		widget.result = err.Error()
   100  		return
   101  	}
   102  	defer func() { _ = response.Body.Close() }()
   103  	var info ipinfo
   104  	err = json.NewDecoder(response.Body).Decode(&info)
   105  	if err != nil {
   106  		widget.result = err.Error()
   107  		return
   108  	}
   109  
   110  	widget.setResult(&info)
   111  }
   112  
   113  func (widget *Widget) setResult(info *ipinfo) {
   114  
   115  	args := utils.ToStrs(widget.settings.args)
   116  
   117  	// if no arguments are defined set default
   118  	if len(args) == 0 {
   119  		args = []string{"ip", "isp", "as", "city", "region", "country", "coordinates", "postalCode", "organization", "timezone"}
   120  	}
   121  
   122  	format := ""
   123  
   124  	for _, arg := range args {
   125  		if val, ok := argLookup[strings.ToLower(arg)]; ok {
   126  			format = format + formatableText(val, strings.ToLower(arg))
   127  		}
   128  	}
   129  
   130  	resultTemplate, _ := template.New("ipinfo_result").Parse(format)
   131  
   132  	resultBuffer := new(bytes.Buffer)
   133  
   134  	err := resultTemplate.Execute(resultBuffer, map[string]string{
   135  		"nameColor":     widget.settings.colors.name,
   136  		"valueColor":    widget.settings.colors.value,
   137  		"ip":            info.Query,
   138  		"isp":           info.ISP,
   139  		"as":            info.AS,
   140  		"asname":        info.ASName,
   141  		"district":      info.District,
   142  		"city":          info.City,
   143  		"region":        info.Region,
   144  		"regionname":    info.RegionName,
   145  		"country":       info.Country,
   146  		"countrycode":   info.CountryCode,
   147  		"continent":     info.Continent,
   148  		"continentcode": info.ContinentCode,
   149  		"coordinates":   strconv.FormatFloat(info.Latitude, 'f', 6, 64) + "," + strconv.FormatFloat(info.Longitude, 'f', 6, 64),
   150  		"postalcode":    info.PostalCode,
   151  		"currency":      info.Currency,
   152  		"organization":  info.Organization,
   153  		"timezone":      info.Timezone,
   154  		"reversedns":    info.ReverseDNS,
   155  	})
   156  
   157  	if err != nil {
   158  		widget.result = err.Error()
   159  	}
   160  
   161  	widget.result = resultBuffer.String()
   162  }
   163  
   164  func formatableText(key, value string) string {
   165  	return fmt.Sprintf(" [{{.nameColor}}]%s: [{{.valueColor}}]{{.%s}}\n", key, value)
   166  }