Skip to content

Commit

Permalink
cmd/trayscale: add netcheck functionality (#23)
Browse files Browse the repository at this point in the history
* tailscale: add support for getting netcheck reports

* internal/set: add

* cmd/gtkbuildergen: remove double-use of values as children

* cmd/trayscale: add non-functional `NetCheckGroup`

* cmd/trayscale: move `NetCheckGroup` further down the window

* tailscale: disable automatic `netcheck` logging

* cmd/gtkbuildergen: add `visible` property

* cmd/trayscale: add basic netcheck functionality

* tailscale: return the DERP map from `NetCheck()`

* cmd/trayscale: add a bunch more netcheck information

Also add a `false` boolean icon.

* meta: update some dependencies

* internal/xmaps: add

* cmd/trayscale: add full list of DERP latencies

* tailscale: make it possible do a full DERP latency check

* cmd/trayscale: do a full DERP latency check

* cmd/trayscale: add a bunch more netcheck info

* cmd/trayscale: add yet more netcheck info

* cmd/trayscale: combine IP address and status into the same row
  • Loading branch information
DeedleFake authored Sep 19, 2022
1 parent 4064a83 commit 6e98d11
Show file tree
Hide file tree
Showing 13 changed files with 504 additions and 15 deletions.
7 changes: 5 additions & 2 deletions cmd/gtkbuildergen/init.tmpl
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
{{- $id := or .ID "parent" -}}
{{- $used := newValueSet -}}

{{range .Properties -}}
{{$id}}.SetObjectProperty({{.Name | printf "%q"}}, {{.Value}})
{{$id}}.SetObjectProperty({{.Name | printf "%q"}}, {{$used.Add .Value}})
{{end -}}
{{range $i, $c := .Children -}}
{{- $cid := or .Object.ID (printf "%v%v" $id $i) -}}
{{$id}}.{{$.Type.AddChild .Type $cid}}
{{if not ($used.Has $cid) -}}
{{$id}}.{{$.Type.AddChild .Type $cid}}
{{end -}}
{{end}}
5 changes: 5 additions & 0 deletions cmd/gtkbuildergen/tmpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"embed"
_ "embed"
"text/template"

"deedles.dev/trayscale/internal/set"
)

var (
Expand All @@ -28,6 +30,9 @@ func init() {
}
return false
},
"newValueSet": func() set.Set[string] {
return make(set.Set[string])
},
})
tmpl = template.Must(tmpl.ParseFS(tmplFS, "*.tmpl"))
}
4 changes: 2 additions & 2 deletions cmd/gtkbuildergen/uidef.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ var (

func (p Property) Value() string {
switch p.Name {
case "width-request", "height-request", "default-width", "default-height", "content", "stack", "spacing", "margin-top", "margin-bottom":
case "width-request", "height-request", "default-width", "default-height", "content", "stack", "spacing", "margin-top", "margin-bottom", "header-suffix":
return p.RawValue
case "show-start-title-buttons", "show-end-title-buttons", "primary", "vexpand", "hexpand":
case "show-start-title-buttons", "show-end-title-buttons", "primary", "vexpand", "hexpand", "visible":
b, err := strconv.ParseBool(p.RawValue)
if err != nil {
return p.RawValue
Expand Down
57 changes: 51 additions & 6 deletions cmd/trayscale/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"deedles.dev/mk"
"deedles.dev/trayscale/internal/version"
"deedles.dev/trayscale/internal/xmaps"
"deedles.dev/trayscale/internal/xslices"
"deedles.dev/trayscale/tailscale"
"github.com/diamondburned/gotk4-adwaita/pkg/adw"
Expand Down Expand Up @@ -141,6 +142,7 @@ func (a *App) updatePeerPage(page *peerPage, peer *ipnstate.PeerStatus, prefs *i
page.container.AdvertiseExitNodeSwitch.SetState(prefs.AdvertisesExitNode())
page.container.AllowLANAccessSwitch.SetState(prefs.ExitNodeAllowLANAccess)
}
page.container.NetCheckGroup.SetVisible(self)

page.container.MiscGroup.SetVisible(!self)
page.container.ExitNodeRow.SetVisible(peer.ExitNodeOption)
Expand All @@ -152,12 +154,7 @@ func (a *App) updatePeerPage(page *peerPage, peer *ipnstate.PeerStatus, prefs *i
page.container.LastSeenRow.SetVisible(!peer.Online)
page.container.LastWrite.SetText(formatTime(peer.LastWrite))
page.container.LastHandshake.SetText(formatTime(peer.LastHandshake))

var onlineIcon string
if peer.Online {
onlineIcon = "emblem-ok-symbolic"
}
page.container.Online.SetFromIconName(onlineIcon)
page.container.Online.SetFromIconName(boolIcon(peer.Online))
}

func (a *App) notify(status bool) {
Expand Down Expand Up @@ -393,5 +390,53 @@ func (a *App) newPeerPage(peer *ipnstate.PeerStatus) *peerPage {
return true
})

var latencyRows []gtk.Widgetter
page.container.NetCheckButton.ConnectClicked(func() {
r, dm, err := a.TS.NetCheck(context.TODO(), true)
if err != nil {
log.Printf("Error: netcheck: %v", err)
return
}

page.container.LastNetCheck.SetText(formatTime(time.Now()))
page.container.UDPRow.SetVisible(true)
page.container.UDP.SetFromIconName(boolIcon(r.UDP))
page.container.IPv4Row.SetVisible(true)
page.container.IPv4Icon.SetVisible(!r.IPv4)
page.container.IPv4Icon.SetFromIconName(boolIcon(r.IPv4))
page.container.IPv4Addr.SetVisible(r.IPv4)
page.container.IPv4Addr.SetText(r.GlobalV4)
page.container.IPv6Row.SetVisible(true)
page.container.IPv6Icon.SetVisible(!r.IPv6)
page.container.IPv6Icon.SetFromIconName(boolIcon(r.IPv6))
page.container.IPv6Addr.SetVisible(r.IPv6)
page.container.IPv6Addr.SetText(r.GlobalV6)
page.container.UPnPRow.SetVisible(true)
page.container.UPnP.SetFromIconName(optBoolIcon(r.UPnP))
page.container.PMPRow.SetVisible(true)
page.container.PMP.SetFromIconName(optBoolIcon(r.PMP))
page.container.PCPRow.SetVisible(true)
page.container.PCP.SetFromIconName(optBoolIcon(r.PCP))
page.container.HairPinningRow.SetVisible(true)
page.container.HairPinning.SetFromIconName(optBoolIcon(r.HairPinning))
page.container.PreferredDERPRow.SetVisible(true)
page.container.PreferredDERP.SetText(dm.Regions[r.PreferredDERP].RegionName)

page.container.DERPLatencies.SetVisible(true)
for _, row := range latencyRows {
page.container.DERPLatencies.Remove(row)
}
latencyRows = latencyRows[:0]
latencies := xmaps.Entries(r.RegionLatency)
slices.SortFunc(latencies, func(e1, e2 xmaps.Entry[int, time.Duration]) bool { return e1.Val < e2.Val })
for _, lat := range latencies {
row := adw.NewActionRow()
row.SetTitle(dm.Regions[lat.Key].RegionName)
row.AddSuffix(gtk.NewLabel(lat.Val.String()))
page.container.DERPLatencies.AddRow(row)
latencyRows = append(latencyRows, row)
}
})

return &page
}
107 changes: 107 additions & 0 deletions cmd/trayscale/peerpage.ui
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,113 @@
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="NetCheckGroup">
<property name="header-suffix">NetCheckButton</property>
<property name="title">Network Check</property>
<child>
<object class="GtkButton" id="NetCheckButton">
<property name="icon-name">view-refresh-symbolic</property>
</object>
</child>
<child>
<object class="AdwActionRow" id="LastNetCheckRow">
<property name="title">Last run</property>
<child>
<object class="GtkLabel" id="LastNetCheck">
<property name="label">Never</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="UDPRow">
<property name="title">UDP</property>
<property name="visible">False</property>
<child>
<object class="GtkImage" id="UDP"/>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="IPv4Row">
<property name="title">IPv4</property>
<property name="visible">False</property>
<child>
<object class="GtkImage" id="IPv4Icon"/>
</child>
<child>
<object class="GtkLabel" id="IPv4Addr"/>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="IPv6Row">
<property name="title">IPv6</property>
<property name="visible">False</property>
<child>
<object class="GtkImage" id="IPv6Icon"/>
</child>
<child>
<object class="GtkLabel" id="IPv6Addr"/>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="UPnPRow">
<property name="title">UPnP</property>
<property name="visible">False</property>
<child>
<object class="GtkImage" id="UPnP"/>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="PMPRow">
<property name="title">NAT port mapping protocol</property>
<property name="visible">False</property>
<child>
<object class="GtkImage" id="PMP"/>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="PCPRow">
<property name="title">Port control protocol</property>
<property name="visible">False</property>
<child>
<object class="GtkImage" id="PCP"/>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="HairPinningRow">
<property name="title">Hair pinning</property>
<property name="visible">False</property>
<child>
<object class="GtkImage" id="HairPinning"/>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="PreferredDERPRow">
<property name="title">Preferred DERP</property>
<property name="visible">False</property>
<child>
<object class="GtkLabel" id="PreferredDERP">
<property name="label">Never</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwExpanderRow" id="DERPLatencies">
<property name="title">DERP Latencies</property>
<property name="visible">False</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="MiscGroup">
<property name="title">Misc.</property>
Expand Down
53 changes: 50 additions & 3 deletions cmd/trayscale/trayscale.cmb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
(2,5,"AdwClamp",None,3,None,None,None,None,None),
(2,7,"GtkBox",None,5,None,None,None,None,None),
(2,8,"AdwPreferencesGroup","IPGroup",7,None,None,None,None,None),
(2,9,"AdwPreferencesGroup","MiscGroup",7,None,None,None,2,None),
(2,9,"AdwPreferencesGroup","MiscGroup",7,None,None,None,3,None),
(2,11,"AdwActionRow","ExitNodeRow",9,None,None,None,None,None),
(2,12,"AdwActionRow","RxBytesRow",9,None,None,None,6,None),
(2,13,"AdwActionRow","TxBytesRow",9,None,None,None,7,None),
Expand All @@ -43,7 +43,30 @@
(2,28,"AdwActionRow","AdvertiseExitNodeRow",27,None,None,None,None,None),
(2,29,"GtkSwitch","AdvertiseExitNodeSwitch",28,None,None,None,None,None),
(2,30,"AdwActionRow","AllowLANAccessRow",27,None,None,None,1,None),
(2,31,"GtkSwitch","AllowLANAccessSwitch",30,None,None,None,None,None)
(2,31,"GtkSwitch","AllowLANAccessSwitch",30,None,None,None,None,None),
(2,32,"AdwPreferencesGroup","NetCheckGroup",7,None,None,None,2,None),
(2,33,"GtkButton","NetCheckButton",32,None,None,None,None,None),
(2,34,"AdwActionRow","UDPRow",32,None,None,None,4,None),
(2,36,"AdwActionRow","IPv4Row",32,None,None,None,5,None),
(2,38,"AdwActionRow","IPv6Row",32,None,None,None,6,None),
(2,39,"GtkImage","UDP",34,None,None,None,None,None),
(2,40,"GtkImage","IPv4Icon",36,None,None,None,None,None),
(2,41,"GtkImage","IPv6Icon",38,None,None,None,None,None),
(2,42,"AdwActionRow","LastNetCheckRow",32,None,None,None,1,None),
(2,43,"GtkLabel","LastNetCheck",42,None,None,None,None,None),
(2,44,"AdwActionRow","PreferredDERPRow",32,None,None,None,11,None),
(2,45,"GtkLabel","PreferredDERP",44,None,None,None,None,None),
(2,48,"AdwActionRow","HairPinningRow",32,None,None,None,10,None),
(2,49,"GtkImage","HairPinning",48,None,None,None,None,None),
(2,51,"AdwExpanderRow","DERPLatencies",32,None,None,None,12,None),
(2,52,"AdwActionRow","UPnPRow",32,None,None,None,7,None),
(2,53,"GtkImage","UPnP",52,None,None,None,None,None),
(2,54,"AdwActionRow","PMPRow",32,None,None,None,8,None),
(2,55,"GtkImage","PMP",54,None,None,None,None,None),
(2,56,"AdwActionRow","PCPRow",32,None,None,None,9,None),
(2,57,"GtkImage","PCP",56,None,None,None,None,None),
(2,62,"GtkLabel","IPv4Addr",36,None,None,None,1,None),
(2,63,"GtkLabel","IPv6Addr",38,None,None,None,1,None)
</object>
<object_property>
(1,1,"AdwApplicationWindow","content","4",None,None,None,None,None),
Expand Down Expand Up @@ -84,6 +107,30 @@
(2,29,"GtkWidget","margin-top","12",None,None,None,None,None),
(2,30,"AdwPreferencesRow","title","Allow LAN access",None,None,None,None,None),
(2,31,"GtkWidget","margin-bottom","12",None,None,None,None,None),
(2,31,"GtkWidget","margin-top","12",None,None,None,None,None)
(2,31,"GtkWidget","margin-top","12",None,None,None,None,None),
(2,32,"AdwPreferencesGroup","header-suffix","33",None,None,None,None,None),
(2,32,"AdwPreferencesGroup","title","Network Check",None,None,None,None,None),
(2,33,"GtkButton","icon-name","view-refresh-symbolic",None,None,None,None,None),
(2,34,"AdwPreferencesRow","title","UDP",None,None,None,None,None),
(2,34,"GtkWidget","visible","False",None,None,None,None,None),
(2,36,"AdwPreferencesRow","title","IPv4",None,None,None,None,None),
(2,36,"GtkWidget","visible","False",None,None,None,None,None),
(2,38,"AdwPreferencesRow","title","IPv6",None,None,None,None,None),
(2,38,"GtkWidget","visible","False",None,None,None,None,None),
(2,42,"AdwPreferencesRow","title","Last run",None,None,None,None,None),
(2,43,"GtkLabel","label","Never",None,None,None,None,None),
(2,44,"AdwPreferencesRow","title","Preferred DERP",None,None,None,None,None),
(2,44,"GtkWidget","visible","False",None,None,None,None,None),
(2,45,"GtkLabel","label","Never",None,None,None,None,None),
(2,48,"AdwPreferencesRow","title","Hair pinning",None,None,None,None,None),
(2,48,"GtkWidget","visible","False",None,None,None,None,None),
(2,51,"AdwPreferencesRow","title","DERP Latencies",None,None,None,None,None),
(2,51,"GtkWidget","visible","False",None,None,None,None,None),
(2,52,"AdwPreferencesRow","title","UPnP",None,None,None,None,None),
(2,52,"GtkWidget","visible","False",None,None,None,None,None),
(2,54,"AdwPreferencesRow","title","NAT port mapping protocol",None,None,None,None,None),
(2,54,"GtkWidget","visible","False",None,None,None,None,None),
(2,56,"AdwPreferencesRow","title","Port control protocol",None,None,None,None,None),
(2,56,"GtkWidget","visible","False",None,None,None,None,None)
</object_property>
</cambalache-project>
16 changes: 16 additions & 0 deletions cmd/trayscale/trayscale.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"deedles.dev/trayscale"
"deedles.dev/trayscale/tailscale"
"tailscale.com/ipn/ipnstate"
"tailscale.com/types/opt"
)

const (
Expand Down Expand Up @@ -74,6 +75,21 @@ func peerIcon(peer *ipnstate.PeerStatus) string {
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() {
if prof, ok := os.LookupEnv("PPROF"); ok {
file, err := os.Create(prof)
Expand Down
Loading

0 comments on commit 6e98d11

Please sign in to comment.