forked from muka/go-bluetooth
-
Notifications
You must be signed in to change notification settings - Fork 1
/
props.go
95 lines (77 loc) · 1.83 KB
/
props.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package bluez
import (
"reflect"
"github.com/godbus/dbus"
"github.com/muka/go-bluetooth/util"
log "github.com/sirupsen/logrus"
)
type WatchableClient interface {
Client() *Client
Path() dbus.ObjectPath
ToProps() Properties
}
// WatchProperties updates on property changes
func WatchProperties(wprop WatchableClient) (chan *PropertyChanged, error) {
channel, err := wprop.Client().Register(wprop.Path(), PropertiesInterface)
if err != nil {
return nil, err
}
ch := make(chan *PropertyChanged)
go (func() {
for {
if channel == nil {
break
}
sig := <-channel
if sig == nil {
return
}
if sig.Name != PropertiesChanged {
continue
}
if sig.Path != wprop.Path() {
continue
}
iface := sig.Body[0].(string)
changes := sig.Body[1].(map[string]dbus.Variant)
for field, val := range changes {
// updates [*]Properties struct when a property change
s := reflect.ValueOf(wprop.ToProps()).Elem()
// exported field
f := s.FieldByName(field)
if f.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if f.CanSet() {
x := reflect.ValueOf(val.Value())
wprop.ToProps().Lock()
// map[*]variant -> map[*]interface{}
ok, err := util.AssignMapVariantToInterface(f, x)
if err != nil {
log.Errorf("Failed to set %s: %s", f.String(), err)
continue
}
// direct assignment
if !ok {
f.Set(x)
}
wprop.ToProps().Unlock()
}
}
propChanged := &PropertyChanged{
Interface: iface,
Name: field,
Value: val.Value(),
}
ch <- propChanged
}
}
})()
return ch, nil
}
func UnwatchProperties(wprop WatchableClient, ch chan *PropertyChanged) error {
ch <- nil
close(ch)
return nil
}