Skip to content

Commit

Permalink
add SetMustMany
Browse files Browse the repository at this point in the history
* to set many properties at once and to emit only one signal
  • Loading branch information
Stefan Schubert authored and malaupa committed May 16, 2023
1 parent 6cc540d commit 977413d
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 22 deletions.
70 changes: 48 additions & 22 deletions prop/prop.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,32 +278,40 @@ func (p *Properties) Introspection(iface string) []introspect.Property {

// set sets the given property and emits PropertyChanged if appropriate. p.mut
// must already be locked.
func (p *Properties) set(iface, property string, v interface{}) error {
prop := p.m[iface][property]
err := dbus.Store([]interface{}{v}, prop.Value)
func (p *Properties) set(iface string, properties []string, v ...interface{}) error {
var props []interface{}
for _, property := range properties {
props = append(props, p.m[iface][property].Value)
}
err := dbus.Store(v, props...)
if err != nil {
return err
}
return p.emitChange(iface, property)
return p.emitChange(iface, properties...)
}

func (p *Properties) emitChange(iface, property string) error {
prop := p.m[iface][property]
switch prop.Emit {
case EmitFalse:
return nil // do nothing
case EmitInvalidates:
return p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
iface, map[string]dbus.Variant{}, []string{property})
case EmitTrue:
return p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
iface, map[string]dbus.Variant{property: dbus.MakeVariant(prop.Value)},
[]string{})
case EmitConst:
return nil
default:
panic("invalid value for EmitType")
func (p *Properties) emitChange(iface string, properties ...string) error {
changes := make(map[string]dbus.Variant)
invalidates := []string{}

for _, property := range properties {
prop := p.m[iface][property]
switch prop.Emit {
case EmitFalse:
return nil // do nothing
case EmitInvalidates:
invalidates = append(invalidates, property)
case EmitTrue:
changes[property] = dbus.MakeVariant(prop.Value)
case EmitConst:
return nil
default:
panic("invalid value for EmitType")
}
}

return p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
iface, changes, invalidates)
}

// Set implements org.freedesktop.Properties.Set.
Expand All @@ -330,7 +338,7 @@ func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error
return err
}
}
if err := p.set(iface, property, newv.Value()); err != nil {
if err := p.set(iface, []string{property}, newv.Value()); err != nil {
return dbus.MakeFailedError(err)
}
return nil
Expand All @@ -341,7 +349,25 @@ func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error
func (p *Properties) SetMust(iface, property string, v interface{}) {
p.mut.Lock()
defer p.mut.Unlock() // unlock in case of panic
err := p.set(iface, property, v)
err := p.set(iface, []string{property}, v)
if err != nil {
panic(err)
}
}

// SetMustMany sets the values of the given property value map and panics if any interface or
// property name are invalid.
func (p *Properties) SetMustMany(iface string, newValues map[string]interface{}) {
p.mut.Lock()
defer p.mut.Unlock()

properties := make([]string, 0, len(newValues))
values := make([]interface{}, 0, len(newValues))
for key, val := range newValues {
properties = append(properties, key)
values = append(values, val)
}
err := p.set(iface, properties, values...)
if err != nil {
panic(err)
}
Expand Down
70 changes: 70 additions & 0 deletions prop/prop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,73 @@ func TestInt32(t *testing.T) {
t.Errorf("expected r to be int32(101), but was %#v", r)
}
}

func TestMany(t *testing.T) {
srv, err := dbus.SessionBus()
if err != nil {
t.Fatal(err)
}
defer srv.Close()

cli, err := dbus.SessionBus()
if err != nil {
t.Fatal(err)
}
defer cli.Close()

propsSpec := map[string]map[string]*Prop{
"org.guelfey.DBus.Test": {
"one": {
"oneValue",
true,
EmitTrue,
nil,
},
"two": {
0,
true,
EmitInvalidates,
nil,
},
},
}
props := New(srv, "/org/guelfey/DBus/Test", propsSpec)

r := props.GetMust("org.guelfey.DBus.Test", "one")
if r != "oneValue" {
t.Errorf("expected r to be 'oneValue', but was %#v", r)
}
r = props.GetMust("org.guelfey.DBus.Test", "two")
if r != 0 {
t.Errorf("expected r to be 0, but was %#v", r)
}

ready := make(chan struct{})
c := make(chan *dbus.Signal, 1)
go func() {
cli.AddMatchSignal(dbus.WithMatchMember("PropertiesChanged"))
defer cli.RemoveMatchSignal(dbus.WithMatchMember("PropertiesChanged"))

cli.Signal(c)
close(ready)
for sig := range c {
if sig.Name == "org.freedesktop.DBus.Properties.PropertiesChanged" {
c <- sig
}
}
}()

<-ready
props.SetMustMany("org.guelfey.DBus.Test", map[string]interface{}{"one": "otherValue", "two": 1})
sig := <-c

changed := sig.Body[1].(map[string]dbus.Variant)
invalidated := sig.Body[2].([]string)
if len(changed) != 1 || len(invalidated) != 1 {
t.Fatalf("changed len or invalidated len mismatch")
}
if changed["one"].Value() != "otherValue" {
t.Fatalf("changed value mismatch")
}

}

0 comments on commit 977413d

Please sign in to comment.