1# Copyright 2015 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 collections
6import dbus.service
7
8from autotest_lib.client.cros.tendo import peerd_dbus_helper
9from autotest_lib.client.cros.tendo.n_faced_peerd import dbus_property_exposer
10
11IpInfo = collections.namedtuple('IpInfo', ['addr', 'port'])
12
13class Service(dbus_property_exposer.DBusPropertyExposer):
14    """Represents local and remote services."""
15
16
17    def __init__(self, bus, path, peer_id, service_id, service_info, ip_info,
18                 object_manager):
19        """Construct a org.chromium.peerd.Service DBus object.
20
21        @param bus: dbus.Bus object to export this object on.
22        @param path: string object path to export this object at.
23        @param service_id: string peerd service ID.
24        @param service_info: dictionary of string,string items comprising
25                the metadata for the service.
26        @param ip_info: an instance of IpInfo defined above.
27        @param object_manager: an instance of ObjectManager.
28
29        """
30        super(Service, self).__init__(
31                bus, path, peerd_dbus_helper.DBUS_INTERFACE_SERVICE)
32        self.peer_id = peer_id
33        self.service_id = service_id
34        self.service_info = service_info
35        self.ip_info = ip_info
36        # Register properties with the property exposer.
37        self.register_property(peerd_dbus_helper.SERVICE_PROPERTY_PEER_ID,
38                               self._get_peer_id)
39        self.register_property(peerd_dbus_helper.SERVICE_PROPERTY_ID,
40                               self._get_service_id)
41        self.register_property(peerd_dbus_helper.SERVICE_PROPERTY_INFO,
42                               self._get_service_info)
43        self.register_property(peerd_dbus_helper.SERVICE_PROPERTY_IPS,
44                               self._get_ip_info)
45        # Claim the service interface.
46        self._object_manager = object_manager
47        self._path = path
48        self._object_manager.claim_interface(
49                path, peerd_dbus_helper.DBUS_INTERFACE_SERVICE,
50                self.property_getter)
51
52
53    def _get_peer_id(self):
54        """Getter for SERVICE_PROPERTY_PEER_ID.
55
56        @return dbus.String containing this service's peer_id.
57
58        """
59        return dbus.String(self.peer_id)
60
61
62    def _get_service_id(self):
63        """Getter for SERVICE_PROPERTY_ID.
64
65        @return dbus.String containing this service's service_id.
66
67        """
68        return dbus.String(self.service_id)
69
70
71    def _get_service_info(self):
72        """Getter for SERVICE_PROPERTY_INFO.
73
74        @return dbus.Dictionary containing this service's metadata.
75
76        """
77        return dbus.Dictionary(self.service_info, 'ss')
78
79
80    def _get_ip_info(self):
81        """Getter for SERVICE_PROPERTY_IPS.
82
83        @return dbus.Array of dbus.Struct objects containing an array of bytes
84                and a port number.  See DBus API documentation.
85
86        """
87        dbus_port = dbus.UInt16(self.ip_info.port)
88        dbus_ip = dbus.Array([dbus.Byte(int(octet))
89                              for octet in self.ip_info.addr.split('.')])
90        ip_info = dbus.Struct((dbus_ip, dbus_port), signature='ayq')
91        return dbus.Array([ip_info], signature='(ayq)')
92
93
94    def update(self, service_info, ip_info):
95        """Update service metadata and trigger DBus signals.
96
97        @param service_info: see constructor.
98        @param ip_info: see constructor.
99
100        """
101        if service_info != self.service_info:
102            self.service_info = service_info
103            self.on_property_changed(peerd_dbus_helper.SERVICE_PROPERTY_INFO)
104        if ip_info != self.ip_info:
105            self.ip_info = ip_info
106            self.on_property_changed(peerd_dbus_helper.SERVICE_PROPERTY_IPS)
107
108
109    def close(self):
110        """Release interfaces claimed by this object."""
111        self._object_manager.release_interface(
112                self._path, peerd_dbus_helper.DBUS_INTERFACE_SERVICE)
113