libweave: Extract platform independent part of PeerdClient

The rest of PeerdClinet will be moved into buffet.

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

Change-Id: I884cfe377334f8d3fced5a493de8d407bb6bd3ca
Reviewed-on: https://chromium-review.googlesource.com/289945
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
Trybot-Ready: Vitaly Buka <vitalybuka@chromium.org>
Tested-by: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/buffet.gyp b/buffet/buffet.gyp
index 8d22323..a679314 100644
--- a/buffet/buffet.gyp
+++ b/buffet/buffet.gyp
@@ -64,6 +64,7 @@
         '../libweave/src/privet/privet_handler.cc',
         '../libweave/src/privet/privet_manager.cc',
         '../libweave/src/privet/privet_types.cc',
+        '../libweave/src/privet/publisher.cc',
         '../libweave/src/privet/security_manager.cc',
         '../libweave/src/privet/shill_client.cc',
         '../libweave/src/privet/privet_types.cc',
diff --git a/libweave/include/weave/mdns.h b/libweave/include/weave/mdns.h
new file mode 100644
index 0000000..d1b7232
--- /dev/null
+++ b/libweave/include/weave/mdns.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef LIBWEAVE_INCLUDE_WEAVE_MDNS_H_
+#define LIBWEAVE_INCLUDE_WEAVE_MDNS_H_
+
+#include <map>
+#include <string>
+
+#include <base/callback.h>
+
+namespace weave {
+
+class Mdns {
+ public:
+  // Publishes new service on mDns or updates existing one.
+  virtual void PublishService(
+      const std::string& service_name,
+      uint16_t port,
+      const std::map<std::string, std::string>& txt) = 0;
+
+  // Stops publishing service.
+  virtual void StopPublishing(const std::string& service_name) = 0;
+
+  // Returns permanent device ID.
+  // TODO(vitalybuka): Find better place for this information.
+  virtual std::string GetId() const = 0;
+
+ protected:
+  virtual ~Mdns() = default;
+};
+
+}  // namespace weave
+
+#endif  // LIBWEAVE_INCLUDE_WEAVE_MDNS_H_
diff --git a/libweave/src/privet/peerd_client.cc b/libweave/src/privet/peerd_client.cc
index d37740e..1ed7796 100644
--- a/libweave/src/privet/peerd_client.cc
+++ b/libweave/src/privet/peerd_client.cc
@@ -10,12 +10,6 @@
 #include <chromeos/errors/error.h>
 #include <chromeos/strings/string_utils.h>
 
-#include "libweave/src/privet/cloud_delegate.h"
-#include "libweave/src/privet/device_delegate.h"
-#include "libweave/src/privet/wifi_bootstrap_manager.h"
-#include "libweave/src/privet/wifi_ssid_generator.h"
-
-using chromeos::string_utils::Join;
 using org::chromium::peerd::PeerProxy;
 
 namespace weave {
@@ -28,8 +22,6 @@
 // updates relevant for a short amount of time.
 const int kCommitTimeoutSeconds = 1;
 
-// The name of the service we'll expose via peerd.
-const char kPrivetServiceId[] = "privet";
 const char kSelfPath[] = "/org/chromium/peerd/Self";
 
 void OnError(const std::string& operation, chromeos::Error* error) {
@@ -38,16 +30,8 @@
 
 }  // namespace
 
-PeerdClient::PeerdClient(const scoped_refptr<dbus::Bus>& bus,
-                         const DeviceDelegate* device,
-                         const CloudDelegate* cloud,
-                         const WifiDelegate* wifi)
-    : peerd_object_manager_proxy_{bus},
-      device_{device},
-      cloud_{cloud},
-      wifi_{wifi} {
-  CHECK(device_);
-  CHECK(cloud_);
+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(
@@ -64,6 +48,28 @@
   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();
@@ -110,44 +116,16 @@
   // Do nothing if peerd hasn't started yet.
   if (peerd_manager_proxy_ == nullptr)
     return;
-
-  std::string name;
-  std::string model_id;
-  if (!cloud_->GetName(&name, nullptr) ||
-      !cloud_->GetModelId(&model_id, nullptr)) {
-    return;
-  }
-  DCHECK_EQ(model_id.size(), 5U);
-
   VLOG(1) << "Starting peerd advertising.";
-  const uint16_t port = device_->GetHttpEnpoint().first;
+  CHECK_NE(port_, 0);
+  CHECK(!service_name_.empty());
+  CHECK(!txt_.empty());
   std::map<std::string, chromeos::Any> mdns_options{
-      {"port", chromeos::Any{port}},
+      {"port", chromeos::Any{port_}},
   };
-  DCHECK_NE(port, 0);
-
-  std::string services;
-  if (!cloud_->GetServices().empty())
-    services += "_";
-  services += Join(",_", cloud_->GetServices());
-
-  std::map<std::string, std::string> txt_record{
-      {"txtvers", "3"},
-      {"ty", name},
-      {"services", services},
-      {"id", GetId()},
-      {"mmid", model_id},
-      {"flags", WifiSsidGenerator{cloud_, wifi_}.GenerateFlags()},
-  };
-
-  if (!cloud_->GetCloudId().empty())
-    txt_record.emplace("gcd_id", cloud_->GetCloudId());
-
-  if (!cloud_->GetDescription().empty())
-    txt_record.emplace("note", cloud_->GetDescription());
 
   peerd_manager_proxy_->ExposeServiceAsync(
-      kPrivetServiceId, txt_record, {{"mdns", mdns_options}}, base::Closure(),
+      service_name_, txt_, {{"mdns", mdns_options}}, base::Closure(),
       base::Bind(&OnError, "ExposeService"));
 }
 
@@ -156,12 +134,14 @@
     return;
 
   VLOG(1) << "Stopping peerd advertising.";
-  peerd_manager_proxy_->RemoveExposedServiceAsync(
-      kPrivetServiceId, base::Closure(), base::Bind(&OnError, "RemoveService"));
+  if (!service_name_.empty()) {
+    peerd_manager_proxy_->RemoveExposedServiceAsync(
+        service_name_, base::Closure(), base::Bind(&OnError, "RemoveService"));
+  }
 }
 
 void PeerdClient::UpdateImpl() {
-  if (device_->GetHttpEnpoint().first == 0)
+  if (port_ == 0)
     return RemoveService();
   ExposeService();
 }
diff --git a/libweave/src/privet/peerd_client.h b/libweave/src/privet/peerd_client.h
index b75e253..de90248 100644
--- a/libweave/src/privet/peerd_client.h
+++ b/libweave/src/privet/peerd_client.h
@@ -5,14 +5,15 @@
 #ifndef LIBWEAVE_SRC_PRIVET_PEERD_CLIENT_H_
 #define LIBWEAVE_SRC_PRIVET_PEERD_CLIENT_H_
 
+#include <map>
 #include <memory>
 #include <string>
 
 #include <base/callback.h>
 #include <base/memory/ref_counted.h>
 
-#include "libweave/src/privet/identity_delegate.h"
 #include "peerd/dbus-proxies.h"
+#include "weave/mdns.h"
 
 namespace dbus {
 class Bus;
@@ -21,26 +22,19 @@
 namespace weave {
 namespace privet {
 
-class CloudDelegate;
-class DeviceDelegate;
-class WifiDelegate;
-
-// Publishes prived service on mDns using peerd.
-class PeerdClient : public IdentityDelegate {
+// Publishes privet service on mDns using peerd.
+class PeerdClient : public Mdns {
  public:
-  PeerdClient(const scoped_refptr<dbus::Bus>& bus,
-              const DeviceDelegate* device,
-              const CloudDelegate* cloud,
-              const WifiDelegate* wifi);
-  ~PeerdClient();
+  explicit PeerdClient(const scoped_refptr<dbus::Bus>& bus);
+  ~PeerdClient() override;
 
-  // Get the unique identifier for this device.  Note that if peerd has
-  // never been seen, this may be the empty string.
+  // 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;
 
-  // Updates published information.  Removes service if HTTP is not alive.
-  void Update();
-
  private:
   void OnPeerdOnline(org::chromium::peerd::ManagerProxy* manager_proxy);
   void OnPeerdOffline(const dbus::ObjectPath& object_path);
@@ -48,6 +42,9 @@
   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();
 
@@ -57,15 +54,17 @@
   // |peerd_manager_proxy_| is owned by |peerd_object_manager_proxy_|.
   org::chromium::peerd::ManagerProxy* peerd_manager_proxy_{nullptr};
 
-  const DeviceDelegate* device_{nullptr};
-  const CloudDelegate* cloud_{nullptr};
-  const WifiDelegate* wifi_{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 privet
diff --git a/libweave/src/privet/privet_manager.cc b/libweave/src/privet/privet_manager.cc
index 698283a..b65ba06 100644
--- a/libweave/src/privet/privet_manager.cc
+++ b/libweave/src/privet/privet_manager.cc
@@ -35,6 +35,7 @@
 #include "libweave/src/privet/device_delegate.h"
 #include "libweave/src/privet/peerd_client.h"
 #include "libweave/src/privet/privet_handler.h"
+#include "libweave/src/privet/publisher.h"
 #include "libweave/src/privet/shill_client.h"
 
 namespace weave {
@@ -88,12 +89,15 @@
     wifi_bootstrap_manager_->Init();
   }
 
-  peerd_client_.reset(new PeerdClient(bus, device_.get(), cloud_.get(),
-                                      wifi_bootstrap_manager_.get()));
+  peerd_client_.reset(new PeerdClient(bus));
+
+  publisher_.reset(new Publisher(device_.get(), cloud_.get(),
+                                 wifi_bootstrap_manager_.get(),
+                                 peerd_client_.get()));
 
   privet_handler_.reset(
       new PrivetHandler(cloud_.get(), device_.get(), security_.get(),
-                        wifi_bootstrap_manager_.get(), peerd_client_.get()));
+                        wifi_bootstrap_manager_.get(), publisher_.get()));
 
   web_server_.reset(new libwebserv::Server);
   web_server_->OnProtocolHandlerConnected(base::Bind(
@@ -195,8 +199,8 @@
 }
 
 void Manager::OnChanged() {
-  if (peerd_client_)
-    peerd_client_->Update();
+  if (publisher_)
+    publisher_->Update();
 }
 
 void Manager::OnConnectivityChanged(bool online) {
@@ -206,8 +210,8 @@
 void Manager::OnProtocolHandlerConnected(ProtocolHandler* protocol_handler) {
   if (protocol_handler->GetName() == ProtocolHandler::kHttp) {
     device_->SetHttpPort(*protocol_handler->GetPorts().begin());
-    if (peerd_client_)
-      peerd_client_->Update();
+    if (publisher_)
+      publisher_->Update();
   } else if (protocol_handler->GetName() == ProtocolHandler::kHttps) {
     device_->SetHttpsPort(*protocol_handler->GetPorts().begin());
     security_->SetCertificateFingerprint(
@@ -218,8 +222,8 @@
 void Manager::OnProtocolHandlerDisconnected(ProtocolHandler* protocol_handler) {
   if (protocol_handler->GetName() == ProtocolHandler::kHttp) {
     device_->SetHttpPort(0);
-    if (peerd_client_)
-      peerd_client_->Update();
+    if (publisher_)
+      publisher_->Update();
   } else if (protocol_handler->GetName() == ProtocolHandler::kHttps) {
     device_->SetHttpsPort(0);
     security_->SetCertificateFingerprint({});
diff --git a/libweave/src/privet/privet_manager.h b/libweave/src/privet/privet_manager.h
index 9ec3984..cb77b12 100644
--- a/libweave/src/privet/privet_manager.h
+++ b/libweave/src/privet/privet_manager.h
@@ -35,6 +35,7 @@
 
 class CommandManager;
 class DeviceRegistrationInfo;
+class Mdns;
 class StateManager;
 
 namespace privet {
@@ -45,6 +46,7 @@
 class DeviceDelegate;
 class PeerdClient;
 class PrivetHandler;
+class Publisher;
 class SecurityManager;
 class ShillClient;
 
@@ -102,6 +104,7 @@
   std::unique_ptr<ApManagerClient> ap_manager_client_;
   std::unique_ptr<WifiBootstrapManager> wifi_bootstrap_manager_;
   std::unique_ptr<PeerdClient> peerd_client_;
+  std::unique_ptr<Publisher> publisher_;
   std::unique_ptr<PrivetHandler> privet_handler_;
   std::unique_ptr<libwebserv::Server> web_server_;
 
diff --git a/libweave/src/privet/publisher.cc b/libweave/src/privet/publisher.cc
new file mode 100644
index 0000000..877aa02
--- /dev/null
+++ b/libweave/src/privet/publisher.cc
@@ -0,0 +1,96 @@
+// 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.
+
+#include "libweave/src/privet/publisher.h"
+
+#include <map>
+
+#include <chromeos/errors/error.h>
+#include <chromeos/strings/string_utils.h>
+
+#include "libweave/src/privet/cloud_delegate.h"
+#include "libweave/src/privet/device_delegate.h"
+#include "libweave/src/privet/wifi_bootstrap_manager.h"
+#include "libweave/src/privet/wifi_ssid_generator.h"
+#include "weave/mdns.h"
+
+using chromeos::string_utils::Join;
+
+namespace weave {
+namespace privet {
+
+namespace {
+
+// The name of the service we'll expose via peerd.
+const char kPrivetServiceId[] = "privet";
+
+}  // namespace
+
+Publisher::Publisher(const DeviceDelegate* device,
+                     const CloudDelegate* cloud,
+                     const WifiDelegate* wifi,
+                     Mdns* mdns)
+    : mdns_{mdns}, device_{device}, cloud_{cloud}, wifi_{wifi} {
+  CHECK(device_);
+  CHECK(cloud_);
+  CHECK(mdns_);
+}
+
+Publisher::~Publisher() {
+  RemoveService();
+}
+
+std::string Publisher::GetId() const {
+  return mdns_->GetId();
+}
+
+void Publisher::Update() {
+  if (device_->GetHttpEnpoint().first == 0)
+    return RemoveService();
+  ExposeService();
+}
+
+void Publisher::ExposeService() {
+  std::string name;
+  std::string model_id;
+  if (!cloud_->GetName(&name, nullptr) ||
+      !cloud_->GetModelId(&model_id, nullptr)) {
+    return;
+  }
+  DCHECK_EQ(model_id.size(), 5U);
+
+  VLOG(1) << "Starting peerd advertising.";
+  const uint16_t port = device_->GetHttpEnpoint().first;
+  DCHECK_NE(port, 0);
+
+  std::string services;
+  if (!cloud_->GetServices().empty())
+    services += "_";
+  services += Join(",_", cloud_->GetServices());
+
+  std::map<std::string, std::string> txt_record{
+      {"txtvers", "3"},
+      {"ty", name},
+      {"services", services},
+      {"id", GetId()},
+      {"mmid", model_id},
+      {"flags", WifiSsidGenerator{cloud_, wifi_}.GenerateFlags()},
+  };
+
+  if (!cloud_->GetCloudId().empty())
+    txt_record.emplace("gcd_id", cloud_->GetCloudId());
+
+  if (!cloud_->GetDescription().empty())
+    txt_record.emplace("note", cloud_->GetDescription());
+
+  mdns_->PublishService(kPrivetServiceId, port, txt_record);
+}
+
+void Publisher::RemoveService() {
+  VLOG(1) << "Stopping service publishing.";
+  mdns_->StopPublishing(kPrivetServiceId);
+}
+
+}  // namespace privet
+}  // namespace weave
diff --git a/libweave/src/privet/publisher.h b/libweave/src/privet/publisher.h
new file mode 100644
index 0000000..1655ae1
--- /dev/null
+++ b/libweave/src/privet/publisher.h
@@ -0,0 +1,60 @@
+// 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.
+
+#ifndef LIBWEAVE_SRC_PRIVET_PUBLISHER_H_
+#define LIBWEAVE_SRC_PRIVET_PUBLISHER_H_
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+
+#include "libweave/src/privet/identity_delegate.h"
+
+namespace dbus {
+class Bus;
+}  // namespace dbus
+
+namespace weave {
+
+class Mdns;
+
+namespace privet {
+
+class CloudDelegate;
+class DeviceDelegate;
+class WifiDelegate;
+
+// Publishes privet service on mDns.
+class Publisher : public IdentityDelegate {
+ public:
+  Publisher(const DeviceDelegate* device,
+            const CloudDelegate* cloud,
+            const WifiDelegate* wifi,
+            Mdns* mdns);
+  ~Publisher() override;
+
+  // IdentityDelegate implementation.
+  std::string GetId() const override;
+
+  // Updates published information.  Removes service if HTTP is not alive.
+  void Update();
+
+ private:
+  void ExposeService();
+  void RemoveService();
+
+  Mdns* mdns_{nullptr};
+
+  const DeviceDelegate* device_{nullptr};
+  const CloudDelegate* cloud_{nullptr};
+  const WifiDelegate* wifi_{nullptr};
+
+  DISALLOW_COPY_AND_ASSIGN(Publisher);
+};
+
+}  // namespace privet
+}  // namespace weave
+
+#endif  // LIBWEAVE_SRC_PRIVET_PUBLISHER_H_