# 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)