ipn{,/ipnlocal}: add ipn.NotifyInitial* flags to WatchIPNBus

To simplify clients getting the initial state when they subscribe.

Change-Id: I2490a5ab2411253717c74265a46a98012b80db82
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/6586/head
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent 197a4f1ae8
commit 8dd1418774

@ -133,6 +133,7 @@ var debugCmd = &ffcli.Command{
FlagSet: (func() *flag.FlagSet { FlagSet: (func() *flag.FlagSet {
fs := newFlagSet("watch-ipn") fs := newFlagSet("watch-ipn")
fs.BoolVar(&watchIPNArgs.netmap, "netmap", true, "include netmap in messages") fs.BoolVar(&watchIPNArgs.netmap, "netmap", true, "include netmap in messages")
fs.BoolVar(&watchIPNArgs.initial, "initial", false, "include initial status")
return fs return fs
})(), })(),
}, },
@ -318,11 +319,16 @@ func runPrefs(ctx context.Context, args []string) error {
} }
var watchIPNArgs struct { var watchIPNArgs struct {
netmap bool netmap bool
initial bool
} }
func runWatchIPN(ctx context.Context, args []string) error { func runWatchIPN(ctx context.Context, args []string) error {
watcher, err := localClient.WatchIPNBus(ctx, 0) var mask ipn.NotifyWatchOpt
if watchIPNArgs.initial {
mask = ipn.NotifyInitialState | ipn.NotifyInitialPrefs | ipn.NotifyInitialNetMap
}
watcher, err := localClient.WatchIPNBus(ctx, mask)
if err != nil { if err != nil {
return err return err
} }

@ -61,6 +61,10 @@ const (
// client either regularly or when they change, without having to ask for // client either regularly or when they change, without having to ask for
// each one via RequestEngineStatus. // each one via RequestEngineStatus.
NotifyWatchEngineUpdates NotifyWatchOpt = 1 << iota NotifyWatchEngineUpdates NotifyWatchOpt = 1 << iota
NotifyInitialState // if set, the first Notify message (sent immediately) will contain the current State + BrowseToURL
NotifyInitialPrefs // if set, the first Notify message (sent immediately) will contain the current Prefs
NotifyInitialNetMap // if set, the first Notify message (sent immediately) will contain the current NetMap
) )
// Notify is a communication from a backend (e.g. tailscaled) to a frontend // Notify is a communication from a backend (e.g. tailscaled) to a frontend

@ -59,6 +59,7 @@ import (
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
"tailscale.com/types/persist" "tailscale.com/types/persist"
"tailscale.com/types/preftype" "tailscale.com/types/preftype"
"tailscale.com/types/ptr"
"tailscale.com/types/views" "tailscale.com/types/views"
"tailscale.com/util/deephash" "tailscale.com/util/deephash"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
@ -534,6 +535,10 @@ func stripKeysFromPrefs(p ipn.PrefsView) ipn.PrefsView {
func (b *LocalBackend) Prefs() ipn.PrefsView { func (b *LocalBackend) Prefs() ipn.PrefsView {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
return b.prefsLocked()
}
func (b *LocalBackend) prefsLocked() ipn.PrefsView {
return stripKeysFromPrefs(b.pm.CurrentPrefs()) return stripKeysFromPrefs(b.pm.CurrentPrefs())
} }
@ -1736,15 +1741,41 @@ func (b *LocalBackend) readPoller() {
func (b *LocalBackend) WatchNotifications(ctx context.Context, mask ipn.NotifyWatchOpt, fn func(roNotify *ipn.Notify) (keepGoing bool)) { func (b *LocalBackend) WatchNotifications(ctx context.Context, mask ipn.NotifyWatchOpt, fn func(roNotify *ipn.Notify) (keepGoing bool)) {
ch := make(chan *ipn.Notify, 128) ch := make(chan *ipn.Notify, 128)
var ini *ipn.Notify
b.mu.Lock() b.mu.Lock()
const initialBits = ipn.NotifyInitialState | ipn.NotifyInitialPrefs | ipn.NotifyInitialNetMap
if mask&initialBits != 0 {
ini = &ipn.Notify{}
if mask&ipn.NotifyInitialState != 0 {
ini.State = ptr.To(b.state)
if b.state == ipn.NeedsLogin {
ini.BrowseToURL = ptr.To(b.authURLSticky)
}
}
if mask&ipn.NotifyInitialPrefs != 0 {
ini.Prefs = ptr.To(b.prefsLocked())
}
if mask&ipn.NotifyInitialNetMap != 0 {
ini.NetMap = b.netMap
}
}
handle := b.notifyWatchers.Add(ch) handle := b.notifyWatchers.Add(ch)
b.mu.Unlock() b.mu.Unlock()
defer func() { defer func() {
b.mu.Lock() b.mu.Lock()
delete(b.notifyWatchers, handle) delete(b.notifyWatchers, handle)
b.mu.Unlock() b.mu.Unlock()
}() }()
if ini != nil {
if !fn(ini) {
return
}
}
// The GUI clients want to know when peers become active or inactive. // The GUI clients want to know when peers become active or inactive.
// They've historically got this information by polling for it, which is // They've historically got this information by polling for it, which is
// wasteful. As a step towards making it efficient, they now set this // wasteful. As a step towards making it efficient, they now set this

Loading…
Cancel
Save