-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobject.go
109 lines (98 loc) · 3.13 KB
/
object.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package dbus
import (
"cmp"
"context"
"encoding/xml"
"fmt"
"maps"
)
// Object is an object exposed by a [Peer].
type Object struct {
p Peer
path ObjectPath
}
// Conn returns the DBus connection associated with the object.
func (o Object) Conn() *Conn { return o.p.Conn() }
// Peer returns the peer that is exposing the object.
func (o Object) Peer() Peer { return o.p }
// Path returns the object's path.
func (o Object) Path() ObjectPath { return o.path }
func (o Object) String() string {
if o.path == "" {
return fmt.Sprintf("%s:<no object>", o.Peer())
}
return fmt.Sprintf("%s:%s", o.Peer(), o.path)
}
func (o Object) Compare(other Object) int {
if ret := o.Peer().Compare(other.Peer()); ret != 0 {
return ret
}
return cmp.Compare(o.Path(), other.Path())
}
// Interface returns a named interface on the object.
//
// The returned value is a local handle only. It does not indicate
// that the object supports the requested interface.
func (o Object) Interface(name string) Interface {
return Interface{
o: o,
name: name,
}
}
// Child returns the named object at the given relative path from the
// current object.
func (o Object) Child(path string) Object {
return Object{
p: o.p,
path: o.path.Child(path),
}
}
// Introspect returns the object's description of the interfaces it
// implements.
//
// Note that while DBus objects are generally well behaved, this
// description is not verified or enforced by the bus, and may not
// accurately reflect the object's implementation.
//
// Introspect returns a [CallError] if the queried object does not
// implement the [org.freedesktop.DBus.Introspectable] interface.
//
// [org.freedesktop.DBus.Introspectable]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable
func (o Object) Introspect(ctx context.Context) (*ObjectDescription, error) {
var resp string
err := o.Interface(ifaceIntrospect).Call(ctx, "Introspect", nil, &resp)
if err != nil {
return nil, err
}
var ret ObjectDescription
if err := xml.Unmarshal([]byte(resp), &ret); err != nil {
return nil, err
}
return &ret, nil
}
// ManagedObjects returns the children of the current Object, and the
// interfaces they implement.
//
// ManagedObjects returns a [CallError] if the queried object does not
// implement the [org.freedesktop.DBus.ObjectManager] interface.
//
// [org.freedesktop.DBus.ObjectManager]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
func (o Object) ManagedObjects(ctx context.Context) (map[Object][]Interface, error) {
// object path -> interface name -> map[property name]value
var resp map[ObjectPath]map[string]map[string]any
err := o.Interface(ifaceObjects).Call(ctx, "GetManagedObjects", nil, &resp)
if err != nil {
return nil, err
}
ret := make(map[Object][]Interface, len(resp))
for path, ifs := range resp {
// TODO: validate that path is a subpath of the current object
child := o.Peer().Object(path)
ifaces := make([]Interface, 0, len(ifs))
for ifname := range maps.Keys(ifs) {
ifaces = append(ifaces, child.Interface(ifname))
}
ret[o.Peer().Object(path)] = ifaces
}
return ret, nil
}