diff --git a/control/controlclient/auto.go b/control/controlclient/auto.go index ba99884bc..54ff7d77c 100644 --- a/control/controlclient/auto.go +++ b/control/controlclient/auto.go @@ -21,6 +21,7 @@ "tailscale.com/logger" "tailscale.com/logtail/backoff" "tailscale.com/tailcfg" + "tailscale.com/types/empty" ) // TODO(apenwarr): eliminate the 'state' variable, as it's now obsolete. @@ -60,7 +61,7 @@ func (s state) String() string { } type Status struct { - LoginFinished *struct{} + LoginFinished *empty.Message Err string URL string Persist *Persist // locally persisted configuration @@ -507,9 +508,9 @@ func (c *Client) sendStatus(who string, err error, url string, nm *NetworkMap) { c.logf("sendStatus: %s: %v\n", who, state) var p *Persist - var fin *struct{} + var fin *empty.Message if state == stateAuthenticated { - fin = &struct{}{} + fin = new(empty.Message) } if nm != nil && loggedIn && synced { pp := c.direct.GetPersist() diff --git a/control/controlclient/controlclient_test.go b/control/controlclient/controlclient_test.go index a764a8c71..4790eec13 100644 --- a/control/controlclient/controlclient_test.go +++ b/control/controlclient/controlclient_test.go @@ -7,6 +7,8 @@ import ( "reflect" "testing" + + "tailscale.com/types/empty" ) func fieldsOf(t reflect.Type) (fields []string) { @@ -55,7 +57,7 @@ func TestStatusEqual(t *testing.T) { }, { &Status{LoginFinished: nil}, - &Status{LoginFinished: new(struct{})}, + &Status{LoginFinished: new(empty.Message)}, false, }, } diff --git a/ipn/backend.go b/ipn/backend.go index 593ab915c..6742e3302 100644 --- a/ipn/backend.go +++ b/ipn/backend.go @@ -9,6 +9,7 @@ "tailscale.com/control/controlclient" "tailscale.com/tailcfg" + "tailscale.com/types/empty" "tailscale.com/wgengine" ) @@ -39,15 +40,15 @@ type EngineStatus struct { // In any given notification, any or all of these may be nil, meaning // that they have not changed. type Notify struct { - Version string // version number of IPN backend - ErrMessage *string // critical error message, if any - LoginFinished *struct{} // event: login process succeeded - State *State // current IPN state has changed - Prefs *Prefs // preferences were changed - NetMap *NetworkMap // new netmap received - Engine *EngineStatus // wireguard engine stats - BrowseToURL *string // UI should open a browser right now - BackendLogID *string // public logtail id used by backend + Version string // version number of IPN backend + ErrMessage *string // critical error message, if any + LoginFinished *empty.Message // event: non-nil when login process succeeded + State *State // current IPN state has changed + Prefs *Prefs // preferences were changed + NetMap *NetworkMap // new netmap received + Engine *EngineStatus // wireguard engine stats + BrowseToURL *string // UI should open a browser right now + BackendLogID *string // public logtail id used by backend } // StateKey is an opaque identifier for a set of LocalBackend state diff --git a/ipn/local.go b/ipn/local.go index d4ee3e609..81ad20c43 100644 --- a/ipn/local.go +++ b/ipn/local.go @@ -17,6 +17,7 @@ "tailscale.com/logger" "tailscale.com/portlist" "tailscale.com/tailcfg" + "tailscale.com/types/empty" "tailscale.com/version" "tailscale.com/wgengine" "tailscale.com/wgengine/filter" @@ -194,8 +195,7 @@ func (b *LocalBackend) Start(opts Options) error { // Auth completed, unblock the engine b.blockEngineUpdates(false) b.authReconfig() - noargs := struct{}{} - b.send(Notify{LoginFinished: &noargs}) + b.send(Notify{LoginFinished: &empty.Message{}}) } if new.Persist != nil { persist := *new.Persist // copy diff --git a/types/empty/message.go b/types/empty/message.go new file mode 100644 index 000000000..4e208ca49 --- /dev/null +++ b/types/empty/message.go @@ -0,0 +1,14 @@ +// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package empty defines an empty struct type. +package empty + +// Message is an empty message. Its purpose is to be used as pointer +// type where nil and non-nil distinguish whether it's set. This is +// used instead of a bool when we want to marshal it as a JSON empty +// object (or null) for the future ability to add other fields, at +// which point callers would define a new struct and not use +// empty.Message. +type Message struct{}