1# Copyright 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import dbus
6import logging
7
8
9DBUS_INTERFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager'
10
11
12def dbus2primitive(value):
13    """Convert values from dbus types to python types.
14
15    @param value: dbus object to convert to a primitive.
16
17    """
18    if isinstance(value, dbus.Boolean):
19        return bool(value)
20    elif isinstance(value, int):
21        return int(value)
22    elif isinstance(value, dbus.UInt16):
23        return long(value)
24    elif isinstance(value, dbus.UInt32):
25        return long(value)
26    elif isinstance(value, dbus.UInt64):
27        return long(value)
28    elif isinstance(value, float):
29        return float(value)
30    elif isinstance(value, str):
31        return str(value)
32    elif isinstance(value, unicode):
33        return str(value)
34    elif isinstance(value, list):
35        return [dbus2primitive(x) for x in value]
36    elif isinstance(value, tuple):
37        return tuple([dbus2primitive(x) for x in value])
38    elif isinstance(value, dict):
39        return dict([(dbus2primitive(k), dbus2primitive(v))
40                     for k,v in value.items()])
41    else:
42        logging.error('Failed to convert dbus object of class: %r',
43                      value.__class__.__name__)
44        return value
45
46
47def get_objects_with_interface(service_name, object_manager_path,
48                               dbus_interface, path_prefix=None,
49                               bus=None):
50    """Get objects that have a particular interface via a property manager.
51
52    @param service_name: string remote service exposing the object manager
53            to query (e.g. 'org.chromium.peerd').
54    @param object_manager_path: string DBus path of object manager on remote
55            service (e.g. '/org/chromium/peerd')
56    @param dbus_interface: string interface of object we're interested in.
57    @param path_prefix: string prefix of DBus path to filter for.  If not
58            None, we'll return only objects in the remote service whose
59            paths start with this prefix.
60    @param bus: dbus.Bus object, defaults to dbus.SystemBus().  Note that
61            normally, dbus.SystemBus() multiplexes a single DBus connection
62            among its instances.
63    @return dict that maps object paths to dicts of interface name to properties
64            exposed by that interface.  This is similar to the structure
65            returned by org.freedesktop.DBus.ObjectManaber.GetManagedObjects().
66
67    """
68    if bus is None:
69        bus = dbus.SystemBus()
70    object_manager = dbus.Interface(
71            bus.get_object(service_name, object_manager_path),
72            dbus_interface=DBUS_INTERFACE_OBJECT_MANAGER)
73    objects = dbus2primitive(object_manager.GetManagedObjects())
74    logging.debug('Saw objects %r', objects)
75    # Filter by interface.
76    objects = [(path, interfaces)
77               for path, interfaces in objects.iteritems()
78               if dbus_interface in interfaces]
79    if path_prefix is not None:
80        objects = [(path, interfaces)
81                   for path, interfaces in objects
82                   if path.startswith(path_prefix)]
83    objects = dict(objects)
84    logging.debug('Filtered objects: %r', objects)
85    return objects
86