@ -248,38 +248,55 @@ type AppConnectorPrefs struct {
}
// MaskedPrefs is a Prefs with an associated bitmask of which fields are set.
// Make sure that the bool you add here maintains the same ordering of fields
// as the Prefs struct, because the ApplyEdits() function below relies on this
// ordering to be the same.
//
// Each FooSet field maps to a corresponding Foo field in Prefs. FooSet can be
// a struct, in which case inner fields of FooSet map to inner fields of Foo in
// Prefs (see AutoUpdateSet for example).
type MaskedPrefs struct {
Prefs
ControlURLSet bool ` json:",omitempty" `
RouteAllSet bool ` json:",omitempty" `
AllowSingleHostsSet bool ` json:",omitempty" `
ExitNodeIDSet bool ` json:",omitempty" `
ExitNodeIPSet bool ` json:",omitempty" `
ExitNodeAllowLANAccessSet bool ` json:",omitempty" `
CorpDNSSet bool ` json:",omitempty" `
RunSSHSet bool ` json:",omitempty" `
RunWebClientSet bool ` json:",omitempty" `
WantRunningSet bool ` json:",omitempty" `
LoggedOutSet bool ` json:",omitempty" `
ShieldsUpSet bool ` json:",omitempty" `
AdvertiseTagsSet bool ` json:",omitempty" `
HostnameSet bool ` json:",omitempty" `
NotepadURLsSet bool ` json:",omitempty" `
ForceDaemonSet bool ` json:",omitempty" `
EggSet bool ` json:",omitempty" `
AdvertiseRoutesSet bool ` json:",omitempty" `
NoSNATSet bool ` json:",omitempty" `
NetfilterModeSet bool ` json:",omitempty" `
OperatorUserSet bool ` json:",omitempty" `
ProfileNameSet bool ` json:",omitempty" `
AutoUpdateSet bool ` json:",omitempty" `
AppConnectorSet bool ` json:",omitempty" `
PostureCheckingSet bool ` json:",omitempty" `
NetfilterKindSet bool ` json:",omitempty" `
ControlURLSet bool ` json:",omitempty" `
RouteAllSet bool ` json:",omitempty" `
AllowSingleHostsSet bool ` json:",omitempty" `
ExitNodeIDSet bool ` json:",omitempty" `
ExitNodeIPSet bool ` json:",omitempty" `
ExitNodeAllowLANAccessSet bool ` json:",omitempty" `
CorpDNSSet bool ` json:",omitempty" `
RunSSHSet bool ` json:",omitempty" `
RunWebClientSet bool ` json:",omitempty" `
WantRunningSet bool ` json:",omitempty" `
LoggedOutSet bool ` json:",omitempty" `
ShieldsUpSet bool ` json:",omitempty" `
AdvertiseTagsSet bool ` json:",omitempty" `
HostnameSet bool ` json:",omitempty" `
NotepadURLsSet bool ` json:",omitempty" `
ForceDaemonSet bool ` json:",omitempty" `
EggSet bool ` json:",omitempty" `
AdvertiseRoutesSet bool ` json:",omitempty" `
NoSNATSet bool ` json:",omitempty" `
NetfilterModeSet bool ` json:",omitempty" `
OperatorUserSet bool ` json:",omitempty" `
ProfileNameSet bool ` json:",omitempty" `
AutoUpdateSet AutoUpdatePrefsMask ` json:",omitempty" `
AppConnectorSet bool ` json:",omitempty" `
PostureCheckingSet bool ` json:",omitempty" `
NetfilterKindSet bool ` json:",omitempty" `
}
type AutoUpdatePrefsMask struct {
CheckSet bool ` json:",omitempty" `
ApplySet bool ` json:",omitempty" `
}
func ( m AutoUpdatePrefsMask ) Pretty ( au AutoUpdatePrefs ) string {
var fields [ ] string
if m . CheckSet {
fields = append ( fields , fmt . Sprintf ( "Check=%v" , au . Check ) )
}
if m . ApplySet {
fields = append ( fields , fmt . Sprintf ( "Apply=%v" , au . Apply ) )
}
return strings . Join ( fields , " " )
}
// ApplyEdits mutates p, assigning fields from m.Prefs for each MaskedPrefs
@ -291,15 +308,36 @@ func (p *Prefs) ApplyEdits(m *MaskedPrefs) {
pv := reflect . ValueOf ( p ) . Elem ( )
mv := reflect . ValueOf ( m ) . Elem ( )
mpv := reflect . ValueOf ( & m . Prefs ) . Elem ( )
fields := mv . NumField ( )
for i := 1 ; i < fields ; i ++ {
if mv . Field ( i ) . Bool ( ) {
newFieldValue := mpv . Field ( i - 1 )
pv . Field ( i - 1 ) . Set ( newFieldValue )
applyPrefsEdits ( mpv , pv , maskFields ( mv ) )
}
func applyPrefsEdits ( src , dst reflect . Value , mask map [ string ] reflect . Value ) {
for n , m := range mask {
switch m . Kind ( ) {
case reflect . Bool :
if m . Bool ( ) {
dst . FieldByName ( n ) . Set ( src . FieldByName ( n ) )
}
case reflect . Struct :
applyPrefsEdits ( src . FieldByName ( n ) , dst . FieldByName ( n ) , maskFields ( m ) )
default :
panic ( fmt . Sprintf ( "unsupported mask field kind %v" , m . Kind ( ) ) )
}
}
}
func maskFields ( v reflect . Value ) map [ string ] reflect . Value {
mask := make ( map [ string ] reflect . Value )
for i := 0 ; i < v . NumField ( ) ; i ++ {
f := v . Type ( ) . Field ( i ) . Name
if ! strings . HasSuffix ( f , "Set" ) {
continue
}
mask [ strings . TrimSuffix ( f , "Set" ) ] = v . Field ( i )
}
return mask
}
// IsEmpty reports whether there are no masks set or if m is nil.
func ( m * MaskedPrefs ) IsEmpty ( ) bool {
if m == nil {
@ -308,7 +346,7 @@ func (m *MaskedPrefs) IsEmpty() bool {
mv := reflect . ValueOf ( m ) . Elem ( )
fields := mv . NumField ( )
for i := 1 ; i < fields ; i ++ {
if mv . Field ( i ) . Bool ( ) {
if ! mv . Field ( i ) . IsZero ( ) {
return false
}
}
@ -347,15 +385,30 @@ func (m *MaskedPrefs) Pretty() string {
for i := 1 ; i < mt . NumField ( ) ; i ++ {
name := mt . Field ( i ) . Name
if mv . Field ( i ) . Bool ( ) {
if ! first {
sb . WriteString ( " " )
mf := mv . Field ( i )
switch mf . Kind ( ) {
case reflect . Bool :
if mf . Bool ( ) {
if ! first {
sb . WriteString ( " " )
}
first = false
f := mpv . Field ( i - 1 )
fmt . Fprintf ( & sb , format ( f ) ,
strings . TrimSuffix ( name , "Set" ) ,
f . Interface ( ) )
}
case reflect . Struct :
if mf . IsZero ( ) {
continue
}
mpf := mpv . Field ( i - 1 )
prettyFn := mf . MethodByName ( "Pretty" )
if ! prettyFn . IsValid ( ) {
panic ( fmt . Sprintf ( "MaskedPrefs field %q is missing the Pretty method" , name ) )
}
first = false
f := mpv . Field ( i - 1 )
fmt . Fprintf ( & sb , format ( f ) ,
strings . TrimSuffix ( name , "Set" ) ,
f . Interface ( ) )
res := prettyFn . Call ( [ ] reflect . Value { mpf } )
fmt . Fprintf ( & sb , "%s={%s}" , strings . TrimSuffix ( name , "Set" ) , res [ 0 ] . String ( ) )
}
}
sb . WriteString ( "}" )