github.com/wtfutil/wtf@v0.43.0/modules/ipaddresses/ipinfo/widget.go (about) 1 package ipinfo 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 log "github.com/wtfutil/wtf/logger" 8 "net" 9 "net/http" 10 "text/template" 11 12 "github.com/rivo/tview" 13 "github.com/wtfutil/wtf/view" 14 ) 15 16 type Widget struct { 17 view.TextWidget 18 19 result string 20 settings *Settings 21 } 22 23 type ipinfo struct { 24 Ip string `json:"ip"` 25 Hostname string `json:"hostname"` 26 City string `json:"city"` 27 Region string `json:"region"` 28 Country string `json:"country"` 29 Coordinates string `json:"loc"` 30 PostalCode string `json:"postal"` 31 Organization string `json:"org"` 32 } 33 34 func NewWidget(tviewApp *tview.Application, redrawChan chan bool, settings *Settings) *Widget { 35 widget := Widget{ 36 TextWidget: view.NewTextWidget(tviewApp, redrawChan, nil, settings.Common), 37 38 settings: settings, 39 } 40 41 widget.View.SetWrap(false) 42 43 return &widget 44 } 45 46 func (widget *Widget) Refresh() { 47 widget.ipinfo() 48 49 widget.Redraw(func() (string, string, bool) { return widget.CommonSettings().Title, widget.result, false }) 50 } 51 52 // this method reads the config and calls ipinfo for ip information 53 func (widget *Widget) ipinfo() { 54 client := &http.Client{} 55 var url string 56 ip, ipv6 := getMyIP(widget.settings.protocolVersion) 57 if ipv6 { 58 url = fmt.Sprintf("https://ipinfo.io/%s", ip.String()) 59 } else { 60 url = "https://ipinfo.io/" 61 } 62 63 req, err := http.NewRequest("GET", url, http.NoBody) 64 if err != nil { 65 widget.result = err.Error() 66 return 67 } 68 req.Header.Set("User-Agent", "curl") 69 if widget.settings.apiToken != "" { 70 req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", widget.settings.apiToken)) 71 } 72 73 response, err := client.Do(req) 74 if err != nil { 75 widget.result = err.Error() 76 return 77 } 78 defer func() { _ = response.Body.Close() }() 79 80 var info ipinfo 81 err = json.NewDecoder(response.Body).Decode(&info) 82 if err != nil { 83 widget.result = err.Error() 84 return 85 } 86 87 widget.setResult(&info) 88 } 89 90 func (widget *Widget) setResult(info *ipinfo) { 91 resultTemplate, _ := template.New("ipinfo_result").Parse( 92 formatableText("IP", "Ip") + 93 formatableText("Hostname", "Hostname") + 94 formatableText("City", "City") + 95 formatableText("Region", "Region") + 96 formatableText("Country", "Country") + 97 formatableText("Loc", "Coordinates") + 98 formatableText("Org", "Organization"), 99 ) 100 101 resultBuffer := new(bytes.Buffer) 102 103 err := resultTemplate.Execute(resultBuffer, map[string]string{ 104 "subheadingColor": widget.settings.Colors.Subheading, 105 "valueColor": widget.settings.Colors.Text, 106 "Ip": info.Ip, 107 "Hostname": info.Hostname, 108 "City": info.City, 109 "Region": info.Region, 110 "Country": info.Country, 111 "Coordinates": info.Coordinates, 112 "PostalCode": info.PostalCode, 113 "Organization": info.Organization, 114 }) 115 116 if err != nil { 117 widget.result = err.Error() 118 } 119 120 widget.result = resultBuffer.String() 121 } 122 123 func formatableText(key, value string) string { 124 return fmt.Sprintf(" [{{.subheadingColor}}]%8s[-:-:-] [{{.valueColor}}]{{.%s}}\n", key, value) 125 } 126 127 // getMyIP provides this system's default IPv4 or IPv6 IP address for routing WAN requests. 128 // It does so by dialing out to a site known to have both an A and AAAA DNS records (IPv6) 129 // The 'net' package is allowed to decide how to connect, connecting to both IPv4 or IPv6 address 130 // depending on the availbility of IP protocols. 131 func getMyIP(version protocolVersion) (ip net.IP, v6 bool) { 132 log.Log(fmt.Sprintf("Protocol version: %s", version)) 133 log.Log(fmt.Sprintf("Network: %s", version.toNetwork())) 134 //fmt.Println("Protocol version: ", version) 135 conn, err := net.Dial(version.toNetwork(), "fast.com:80") 136 if err != nil { 137 return 138 } 139 defer func() { _ = conn.Close() }() 140 141 addr := conn.LocalAddr().(*net.TCPAddr) 142 ip = addr.IP 143 v6 = ip.To4() == nil 144 145 return 146 } 147 148 func (pv protocolVersion) toNetwork() string { 149 switch pv { 150 case ipV4: 151 return "tcp4" 152 case ipV6: 153 return "tcp6" 154 default: 155 return "tcp" 156 } 157 }