# Copyright 2015 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import dbus import dbus.service import logging import time from autotest_lib.client.cros.tendo import peerd_dbus_helper from autotest_lib.client.cros.tendo.n_faced_peerd import dbus_property_exposer from autotest_lib.client.cros.tendo.n_faced_peerd import service class Peer(dbus_property_exposer.DBusPropertyExposer): """Represents local and remote peers.""" def __init__(self, bus, path, peer_id, object_manager, is_self=False): """Construct a org.chromium.peerd.Peer DBus object. @param bus: dbus.Bus object to export this object on. @param path: string object path to export this object at. @param peer_id: string peerd peer ID; a UUID. @param is_self: True iff this object will servce as a self peer. @param object_manager: an instance of ObjectManager. """ super(Peer, self).__init__( bus, path, peerd_dbus_helper.DBUS_INTERFACE_PEER) # Fill in the initial values for our properties. self.uuid = peer_id self._is_self = is_self self._update_last_seen() # Register properties with the property exposer. self.register_property(peerd_dbus_helper.PEER_PROPERTY_ID, self._get_dbus_id) self.register_property(peerd_dbus_helper.PEER_PROPERTY_LAST_SEEN, self._get_dbus_last_seen) # Claim our interace with the object manager. self._object_manager = object_manager self._path = path self._object_manager.claim_interface( path, peerd_dbus_helper.DBUS_INTERFACE_PEER, self.property_getter) # We need to keep a good bit of stuff around because we're responsible # for creating child service objects. self._bus = bus self.services = dict() self._services_counter = 0 def _get_dbus_id(self): """Getter for PEER_PROPERTY_ID. @return dbus.String containing our peer ID. """ return dbus.String(self.uuid) def _get_dbus_last_seen(self): """Getter for PEER_PROPERTY_LAST_SEEN. @return dbus.UInt64 containing the last time this peer was seen in milliseconds since the Unix epoc. """ return dbus.UInt64(int(1000 * self._last_seen_seconds)) def _update_last_seen(self): """Updates our last seen value. This would be a simple call to time.time(), except that peerd has to report a last seen time of 0 for the peer object representing itself. """ if self._is_self: self._last_seen_seconds = 0 else: self._last_seen_seconds = time.time() def close(self): """Releases interfaces claimed over DBus.""" # TODO(wiley) call close on child services. raise NotImplementedError('Peer.close() does not work properly') def update_service(self, service_id, service_info, ip_info): """Update a service associated with this peer. @param service_id: string peerd service ID. @param service_info: dictionary of string,string items comprising the metadata for the service. @param ip_info: an instance of IpInfo defined in service.py. """ if service_id in self.services: self.services[service_id].update(service_info, ip_info) else: self._services_counter += 1 service_path = '%s/services/%d' % (self._path, self._services_counter) self.services[service_id] = service.Service( self._bus, service_path, self.uuid, service_id, service_info, ip_info, self._object_manager) logging.info('service=%s has info %r.', service_id, service_info) self._update_last_seen() self.on_property_changed(peerd_dbus_helper.PEER_PROPERTY_LAST_SEEN) def remove_service(self, service_id): """Remove a service associated with this peer. @param service_id: string peerd service ID. """ removed_service = self.services.pop(service_id, None) if removed_service is not None: removed_service.close() self._update_last_seen() self.on_property_changed(peerd_dbus_helper.PEER_PROPERTY_LAST_SEEN)