-
Notifications
You must be signed in to change notification settings - Fork 15
/
trayscale.go
131 lines (110 loc) · 2.2 KB
/
trayscale.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"context"
_ "embed"
"io"
"os"
"os/signal"
"strings"
"time"
"deedles.dev/trayscale"
"deedles.dev/trayscale/internal/tsutil"
"tailscale.com/ipn/ipnstate"
"tailscale.com/types/opt"
)
const (
appID = "dev.deedles.Trayscale"
prefShowWindowAtStart = "showWindowAtStart"
)
var (
//go:embed status-icon-active.png
statusIconActive []byte
//go:embed status-icon-inactive.png
statusIconInactive []byte
)
func statusIcon(online bool) []byte {
if online {
return statusIconActive
}
return statusIconInactive
}
type enum[T any] struct {
Index int
Val T
}
func enumerate[T any](i int, v T) enum[T] {
return enum[T]{i, v}
}
func formatTime(t time.Time) string {
if t.IsZero() {
return ""
}
return t.Format(time.StampMilli)
}
// must returns v if err is nil. If err is not nil, it panics with
// err's value.
func must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
// readAssetString returns the contents of the given embedded asset as
// a string. It panics if there are any errors.
func readAssetString(file string) string {
var str strings.Builder
f := must(trayscale.Assets().Open(file))
must(io.Copy(&str, f))
return str.String()
}
func peerName(peer *ipnstate.PeerStatus, self bool) string {
const maxNameLength = 30
name := peer.HostName
if len(name) > maxNameLength {
name = name[:maxNameLength-3] + "..."
}
if self {
return name + " [This machine]"
}
if peer.ExitNode {
return name + " [Exit node]"
}
if peer.ExitNodeOption {
return name + " [Exit node option]"
}
return name
}
func peerIcon(peer *ipnstate.PeerStatus) string {
if peer.ExitNode {
return "network-workgroup-symbolic"
}
if peer.ExitNodeOption {
return "network-server-symbolic"
}
return "folder-remote-symbolic"
}
func boolIcon(v bool) string {
if v {
return "emblem-ok-symbolic"
}
return "window-close-symbolic"
}
func optBoolIcon(v opt.Bool) string {
b, ok := v.Get()
if !ok {
return "dialog-question-symbolic"
}
return boolIcon(b)
}
func main() {
pprof()
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
ts := tsutil.Client{
Command: "tailscale",
}
a := App{
TS: &ts,
}
a.Run(ctx)
}