all repos

viye @ 9f9e365d9f5437ceeb417be7809b0c3c43e42601

my shot at reimplementing xiki

viye/internal/plumbing/ip/ip.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
files: support ./ paths; add gobin; add json, 2 months ago
1
package ip
2
3
import (
4
	"context"
5
	"errors"
6
	"io"
7
	"net"
8
	"net/http"
9
	"strings"
10
	"time"
11
12
	"github.com/olexsmir/viye/internal/viye"
13
)
14
15
type Tool struct{}
16
17
func (Tool) Name() string                 { return "ip" }
18
func (Tool) Match(ctx *viye.Context) bool { return len(ctx.Path) == 1 && ctx.Path[0] == "ip" }
19
func (Tool) Execute(ctx *viye.Context) (string, error) {
20
	// TODO: if it's not possile to get  public ip, report only local
21
22
	var buf strings.Builder
23
	buf.WriteString("| ")
24
25
	pip, err := getPublicIP()
26
	if err != nil {
27
		return "", err
28
	}
29
	_, _ = buf.WriteString(pip)
30
	_, _ = buf.WriteString(" / ")
31
32
	lip, err := getLocalIP()
33
	if err != nil {
34
		return "", err
35
	}
36
	_, _ = buf.WriteString(lip)
37
38
	_ = buf.WriteByte('\n')
39
	return buf.String(), nil
40
}
41
42
func getLocalIP() (string, error) {
43
	addrs, err := net.InterfaceAddrs()
44
	if err != nil {
45
		return "", err
46
	}
47
	for _, addr := range addrs {
48
		if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
49
			if ipnet.IP.To4() != nil {
50
				return ipnet.IP.String(), nil
51
			}
52
		}
53
	}
54
	return "", errors.New("couldn't get local error")
55
}
56
57
func getPublicIP() (string, error) {
58
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
59
	defer cancel()
60
61
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://ifconfig.me/ip", nil)
62
	if err != nil {
63
		return "", err
64
	}
65
66
	resp, err := http.DefaultClient.Do(req)
67
	if err != nil {
68
		return "", err
69
	}
70
	defer resp.Body.Close()
71
72
	ip, err := io.ReadAll(resp.Body)
73
	if err != nil {
74
		return "", err
75
	}
76
	return strings.TrimSpace(string(ip)), nil
77
}