buffet: Move platform dependent part of PeerdClient out of libweave

Peerd is brillo specific service.

BUG=brillo:1267
TEST='FEATURES=test emerge-gizmo buffet'

Change-Id: I666da7ba0ed6a6c55472fed8c5f5beb16b562619
Reviewed-on: https://chromium-review.googlesource.com/289914
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
Tested-by: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/buffet.gyp b/buffet/buffet.gyp
index a679314..3c59e0a 100644
--- a/buffet/buffet.gyp
+++ b/buffet/buffet.gyp
@@ -32,6 +32,7 @@
         'dbus_conversion.cc',
         'dbus_constants.cc',
         'manager.cc',
+        'peerd_client.cc',
         '../libweave/src/base_api_handler.cc',
         '../libweave/src/buffet_config.cc',
         '../libweave/src/commands/cloud_command_proxy.cc',
@@ -60,7 +61,6 @@
         '../libweave/src/privet/constants.cc',
         '../libweave/src/privet/device_delegate.cc',
         '../libweave/src/privet/openssl_utils.cc',
-        '../libweave/src/privet/peerd_client.cc',
         '../libweave/src/privet/privet_handler.cc',
         '../libweave/src/privet/privet_manager.cc',
         '../libweave/src/privet/privet_types.cc',
diff --git a/buffet/manager.cc b/buffet/manager.cc
index 85c61c1..f6b27a3 100644
--- a/buffet/manager.cc
+++ b/buffet/manager.cc
@@ -25,6 +25,7 @@
 
 #include "buffet/dbus_command_dispatcher.h"
 #include "buffet/dbus_conversion.h"
+#include "buffet/peerd_client.h"
 #include "weave/enum_to_string.h"
 
 using chromeos::dbus_utils::AsyncEventSequencer;
@@ -54,8 +55,10 @@
 
 void Manager::Start(const weave::Device::Options& options,
                     AsyncEventSequencer* sequencer) {
+  peerd_client_.reset(new PeerdClient{dbus_object_.GetBus()});
+
   device_ = weave::Device::Create();
-  device_->Start(options, &dbus_object_, sequencer);
+  device_->Start(options, peerd_client_.get(), &dbus_object_, sequencer);
 
   command_dispatcher_.reset(new DBusCommandDispacher{
       dbus_object_.GetObjectManager(), device_->GetCommands()});
diff --git a/buffet/manager.h b/buffet/manager.h
index 9dc84d8..e9fcad9 100644
--- a/buffet/manager.h
+++ b/buffet/manager.h
@@ -30,6 +30,8 @@
 
 namespace buffet {
 
+class PeerdClient;
+
 class DBusCommandDispacher;
 
 template<typename... Types>
@@ -114,6 +116,7 @@
   org::chromium::Buffet::ManagerAdaptor dbus_adaptor_{this};
   chromeos::dbus_utils::DBusObject dbus_object_;
 
+  std::unique_ptr<PeerdClient> peerd_client_;
   std::unique_ptr<weave::Device> device_;
   std::unique_ptr<DBusCommandDispacher> command_dispatcher_;
 
diff --git a/buffet/peerd_client.cc b/buffet/peerd_client.cc
new file mode 100644
index 0000000..cfbf64a
--- /dev/null
+++ b/buffet/peerd_client.cc
@@ -0,0 +1,148 @@
+// Copyright 2014 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.
+
+#include "buffet/peerd_client.h"
+
+#include <map>
+
+#include <base/message_loop/message_loop.h>
+#include <chromeos/errors/error.h>
+#include <chromeos/strings/string_utils.h>
+
+using org::chromium::peerd::PeerProxy;
+
+namespace buffet {
+
+namespace {
+
+// Commit changes only if no update request happened during the timeout.
+// Usually updates happen in batches, so we don't want to flood network with
+// updates relevant for a short amount of time.
+const int kCommitTimeoutSeconds = 1;
+
+const char kSelfPath[] = "/org/chromium/peerd/Self";
+
+void OnError(const std::string& operation, chromeos::Error* error) {
+  LOG(ERROR) << operation << " failed:" << error->GetMessage();
+}
+
+}  // namespace
+
+PeerdClient::PeerdClient(const scoped_refptr<dbus::Bus>& bus)
+    : peerd_object_manager_proxy_{bus} {
+  peerd_object_manager_proxy_.SetManagerAddedCallback(
+      base::Bind(&PeerdClient::OnPeerdOnline, weak_ptr_factory_.GetWeakPtr()));
+  peerd_object_manager_proxy_.SetManagerRemovedCallback(
+      base::Bind(&PeerdClient::OnPeerdOffline, weak_ptr_factory_.GetWeakPtr()));
+  peerd_object_manager_proxy_.SetPeerAddedCallback(
+      base::Bind(&PeerdClient::OnNewPeer, weak_ptr_factory_.GetWeakPtr()));
+}
+
+PeerdClient::~PeerdClient() {
+  RemoveService();
+}
+
+std::string PeerdClient::GetId() const {
+  return device_id_;
+}
+
+void PeerdClient::PublishService(
+    const std::string& service_name,
+    uint16_t port,
+    const std::map<std::string, std::string>& txt) {
+  // Only one service supported.
+  CHECK(service_name_.empty() || service_name_ == service_name);
+  service_name_ = service_name;
+  port_ = port;
+  txt_ = txt;
+
+  Update();
+}
+
+void PeerdClient::StopPublishing(const std::string& service_name) {
+  // Only one service supported.
+  CHECK(service_name_.empty() || service_name_ == service_name);
+  service_name_ = service_name;
+  port_ = 0;
+
+  Update();
+}
+
+void PeerdClient::Update() {
+  // Abort pending updates, and wait for more changes.
+  restart_weak_ptr_factory_.InvalidateWeakPtrs();
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE, base::Bind(&PeerdClient::UpdateImpl,
+                            restart_weak_ptr_factory_.GetWeakPtr()),
+      base::TimeDelta::FromSeconds(kCommitTimeoutSeconds));
+}
+
+void PeerdClient::OnNewPeer(PeerProxy* peer) {
+  if (!peer || peer->GetObjectPath().value() != kSelfPath)
+    return;
+  peer->SetPropertyChangedCallback(base::Bind(
+      &PeerdClient::OnPeerPropertyChanged, weak_ptr_factory_.GetWeakPtr()));
+  OnPeerPropertyChanged(peer, PeerProxy::UUIDName());
+}
+
+void PeerdClient::OnPeerPropertyChanged(PeerProxy* peer,
+                                        const std::string& property_name) {
+  if (property_name != PeerProxy::UUIDName() ||
+      peer->GetObjectPath().value() != kSelfPath)
+    return;
+  const std::string new_id{peer->uuid()};
+  if (new_id != device_id_) {
+    device_id_ = new_id;
+    Update();
+  }
+}
+
+void PeerdClient::OnPeerdOnline(
+    org::chromium::peerd::ManagerProxy* manager_proxy) {
+  peerd_manager_proxy_ = manager_proxy;
+  VLOG(1) << "Peerd manager is online at '"
+          << manager_proxy->GetObjectPath().value() << "'.";
+  Update();
+}
+
+void PeerdClient::OnPeerdOffline(const dbus::ObjectPath& object_path) {
+  peerd_manager_proxy_ = nullptr;
+  VLOG(1) << "Peerd manager is now offline.";
+}
+
+void PeerdClient::ExposeService() {
+  // Do nothing if peerd hasn't started yet.
+  if (peerd_manager_proxy_ == nullptr)
+    return;
+  VLOG(1) << "Starting peerd advertising.";
+  CHECK_NE(port_, 0);
+  CHECK(!service_name_.empty());
+  CHECK(!txt_.empty());
+  std::map<std::string, chromeos::Any> mdns_options{
+      {"port", chromeos::Any{port_}},
+  };
+
+  peerd_manager_proxy_->ExposeServiceAsync(
+      service_name_, txt_, {{"mdns", mdns_options}}, base::Closure(),
+      base::Bind(&OnError, "ExposeService"));
+}
+
+void PeerdClient::RemoveService() {
+  if (peerd_manager_proxy_ == nullptr)
+    return;
+
+  VLOG(1) << "Stopping peerd advertising.";
+  if (!service_name_.empty()) {
+    peerd_manager_proxy_->RemoveExposedServiceAsync(
+        service_name_, base::Closure(), base::Bind(&OnError, "RemoveService"));
+  }
+}
+
+void PeerdClient::UpdateImpl() {
+  if (port_ == 0)
+    return RemoveService();
+  ExposeService();
+}
+
+}  // namespace buffet
diff --git a/buffet/peerd_client.h b/buffet/peerd_client.h
new file mode 100644
index 0000000..e24cd32
--- /dev/null
+++ b/buffet/peerd_client.h
@@ -0,0 +1,71 @@
+// Copyright 2014 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.
+
+#ifndef BUFFET_PRIVET_PEERD_CLIENT_H_
+#define BUFFET_PRIVET_PEERD_CLIENT_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <base/callback.h>
+#include <base/memory/ref_counted.h>
+
+#include "peerd/dbus-proxies.h"
+#include "weave/mdns.h"
+
+namespace dbus {
+class Bus;
+}  // namespace dbus
+
+namespace buffet {
+
+// Publishes privet service on mDns using peerd.
+class PeerdClient : public weave::Mdns {
+ public:
+  explicit PeerdClient(const scoped_refptr<dbus::Bus>& bus);
+  ~PeerdClient() override;
+
+  // Mdns implementation.
+  void PublishService(const std::string& service_name,
+                      uint16_t port,
+                      const std::map<std::string, std::string>& txt) override;
+  void StopPublishing(const std::string& service_name) override;
+  std::string GetId() const override;
+
+ private:
+  void OnPeerdOnline(org::chromium::peerd::ManagerProxy* manager_proxy);
+  void OnPeerdOffline(const dbus::ObjectPath& object_path);
+  void OnNewPeer(org::chromium::peerd::PeerProxy* peer_proxy);
+  void OnPeerPropertyChanged(org::chromium::peerd::PeerProxy* peer_proxy,
+                             const std::string& property_name);
+
+  // Updates published information.  Removes service if HTTP is not alive.
+  void Update();
+
+  void ExposeService();
+  void RemoveService();
+
+  void UpdateImpl();
+
+  org::chromium::peerd::ObjectManagerProxy peerd_object_manager_proxy_;
+  // |peerd_manager_proxy_| is owned by |peerd_object_manager_proxy_|.
+  org::chromium::peerd::ManagerProxy* peerd_manager_proxy_{nullptr};
+
+  // Cached value of the device ID that we got from peerd.
+  std::string device_id_;
+
+  std::string service_name_;
+  uint16_t port_{0};
+  std::map<std::string, std::string> txt_;
+
+  base::WeakPtrFactory<PeerdClient> restart_weak_ptr_factory_{this};
+  base::WeakPtrFactory<PeerdClient> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(PeerdClient);
+};
+
+}  // namespace buffet
+
+#endif  // BUFFET_PRIVET_PEERD_CLIENT_H_