ipn: implement Prefs.Equals efficiently.

Signed-off-by: David Anderson <dave@natulte.net>
This commit is contained in:
David Anderson
2020-02-17 15:01:23 -08:00
parent a5b84fa921
commit 59ba2e6316
4 changed files with 329 additions and 34 deletions

View File

@@ -36,32 +36,57 @@ type Prefs struct {
}
// IsEmpty reports whether p is nil or pointing to a Prefs zero value.
func (uc *Prefs) IsEmpty() bool { return uc == nil || uc.Equals(&Prefs{}) }
func (p *Prefs) IsEmpty() bool { return p == nil || p.Equals(&Prefs{}) }
func (uc *Prefs) Pretty() string {
var ucp string
if uc.Persist != nil {
ucp = uc.Persist.Pretty()
func (p *Prefs) Pretty() string {
var pp string
if p.Persist != nil {
pp = p.Persist.Pretty()
} else {
ucp = "Persist=nil"
pp = "Persist=nil"
}
return fmt.Sprintf("Prefs{ra=%v mesh=%v dns=%v want=%v notepad=%v pf=%v routes=%v %v}",
uc.RouteAll, uc.AllowSingleHosts, uc.CorpDNS, uc.WantRunning,
uc.NotepadURLs, uc.UsePacketFilter, uc.AdvertiseRoutes, ucp)
p.RouteAll, p.AllowSingleHosts, p.CorpDNS, p.WantRunning,
p.NotepadURLs, p.UsePacketFilter, p.AdvertiseRoutes, pp)
}
func (uc *Prefs) ToBytes() []byte {
data, err := json.MarshalIndent(uc, "", "\t")
func (p *Prefs) ToBytes() []byte {
data, err := json.MarshalIndent(p, "", "\t")
if err != nil {
log.Fatalf("Prefs marshal: %v\n", err)
}
return data
}
func (uc *Prefs) Equals(uc2 *Prefs) bool {
b1 := uc.ToBytes()
b2 := uc2.ToBytes()
return bytes.Equal(b1, b2)
func (p *Prefs) Equals(p2 *Prefs) bool {
if p == nil && p2 == nil {
return true
}
if p == nil || p2 == nil {
return false
}
return p != nil && p2 != nil &&
p.RouteAll == p2.RouteAll &&
p.AllowSingleHosts == p2.AllowSingleHosts &&
p.CorpDNS == p2.CorpDNS &&
p.WantRunning == p2.WantRunning &&
p.NotepadURLs == p2.NotepadURLs &&
p.UsePacketFilter == p2.UsePacketFilter &&
compareIPNets(p.AdvertiseRoutes, p2.AdvertiseRoutes) &&
p.Persist.Equals(p2.Persist)
}
func compareIPNets(a, b []*net.IPNet) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if !a[i].IP.Equal(b[i].IP) || !bytes.Equal(a[i].Mask, b[i].Mask) {
return false
}
}
return true
}
func NewPrefs() Prefs {
@@ -78,45 +103,45 @@ func NewPrefs() Prefs {
}
func PrefsFromBytes(b []byte, enforceDefaults bool) (Prefs, error) {
uc := NewPrefs()
p := NewPrefs()
if len(b) == 0 {
return uc, nil
return p, nil
}
persist := &controlclient.Persist{}
err := json.Unmarshal(b, persist)
if err == nil && (persist.Provider != "" || persist.LoginName != "") {
// old-style relaynode config; import it
uc.Persist = persist
p.Persist = persist
} else {
err = json.Unmarshal(b, &uc)
err = json.Unmarshal(b, &p)
if err != nil {
log.Printf("Prefs parse: %v: %v\n", err, b)
}
}
if enforceDefaults {
uc.RouteAll = true
uc.AllowSingleHosts = true
p.RouteAll = true
p.AllowSingleHosts = true
}
return uc, err
return p, err
}
func (uc *Prefs) Copy() *Prefs {
uc2, err := PrefsFromBytes(uc.ToBytes(), false)
func (p *Prefs) Copy() *Prefs {
p2, err := PrefsFromBytes(p.ToBytes(), false)
if err != nil {
log.Fatalf("Prefs was uncopyable: %v\n", err)
}
return &uc2
return &p2
}
func LoadPrefs(filename string, enforceDefaults bool) *Prefs {
log.Printf("Loading prefs %v\n", filename)
data, err := ioutil.ReadFile(filename)
uc := NewPrefs()
p := NewPrefs()
if err != nil {
log.Printf("Read: %v: %v\n", filename, err)
goto fail
}
uc, err = PrefsFromBytes(data, enforceDefaults)
p, err = PrefsFromBytes(data, enforceDefaults)
if err != nil {
log.Printf("Parse: %v: %v\n", filename, err)
goto fail
@@ -124,8 +149,8 @@ func LoadPrefs(filename string, enforceDefaults bool) *Prefs {
goto post
fail:
log.Printf("failed to load config. Generating a new one.\n")
uc = NewPrefs()
uc.WantRunning = true
p = NewPrefs()
p.WantRunning = true
post:
// Update: we changed our minds :)
// Versabank would like to persist the setting across reboots, for now,
@@ -138,15 +163,15 @@ post:
// know how, rebooting will fix it.
// We still persist WantRunning just in case we change our minds on
// this topic.
uc.WantRunning = true
p.WantRunning = true
}
log.Printf("Loaded prefs %v %v\n", filename, uc.Pretty())
return &uc
log.Printf("Loaded prefs %v %v\n", filename, p.Pretty())
return &p
}
func SavePrefs(filename string, uc *Prefs) {
log.Printf("Saving prefs %v %v\n", filename, uc.Pretty())
data := uc.ToBytes()
func SavePrefs(filename string, p *Prefs) {
log.Printf("Saving prefs %v %v\n", filename, p.Pretty())
data := p.ToBytes()
os.MkdirAll(filepath.Dir(filename), 0700)
if err := atomicfile.WriteFile(filename, data, 0666); err != nil {
log.Printf("SavePrefs: %v\n", err)