Buffet: Phase 1 of GCD device registration workflow

Implemented the basic device registration workflow in buffet daemon.

Updated buffet_client to perform/test device registration:

Check for device registration:
  buffet_client cr

Getting registered device information:
  buffet_client di

Begin registration (with all default values):
  buffet_client sr

Begin registration with custom parameters:
  buffet_client sr "service_url=http://localhost/buffet&device_kind=coffeePot"

Finalize registration:
  buffet_client fr 4/FsXprlpVsmPw6z7ro7aqU156Eh6V.0ktCYeVc3DwYEnp6UAPFm0GAey3PigI

BUG=chromium:363348
TEST=unit tests passed.

Change-Id: Id8a90b66fbdc366eaa9f62caa82a7cb0abc2e638
Reviewed-on: https://chromium-review.googlesource.com/195082
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/buffet_client.cc b/buffet/buffet_client.cc
index edd6e87..dba2f4d 100644
--- a/buffet/buffet_client.cc
+++ b/buffet/buffet_client.cc
@@ -8,17 +8,21 @@
 #include <base/command_line.h>
 #include <base/logging.h>
 #include <base/memory/scoped_ptr.h>
+#include <base/values.h>
 #include <dbus/bus.h>
 #include <dbus/object_proxy.h>
 #include <dbus/message.h>
 #include <sysexits.h>
+#include <dbus/values_util.h>
 
 #include "buffet/dbus_constants.h"
 #include "buffet/dbus_manager.h"
+#include "buffet/data_encoding.h"
 
 using namespace buffet::dbus_constants;
 
 namespace {
+static const int default_timeout_ms = 1000;
 
 dbus::ObjectProxy* GetBuffetDBusProxy(dbus::Bus *bus,
                                       const std::string& object_path) {
@@ -28,11 +32,10 @@
 }
 
 bool CallTestMethod(dbus::ObjectProxy* proxy) {
-  int timeout_ms = 1000;
   dbus::MethodCall method_call(buffet::dbus_constants::kRootInterface,
                                buffet::dbus_constants::kRootTestMethod);
-  scoped_ptr<dbus::Response> response(proxy->CallMethodAndBlock(&method_call,
-                                                                timeout_ms));
+  scoped_ptr<dbus::Response> response(
+    proxy->CallMethodAndBlock(&method_call, default_timeout_ms));
   if (!response) {
     std::cout << "Failed to receive a response." << std::endl;
     return false;
@@ -41,33 +44,119 @@
   return true;
 }
 
-bool CallManagerRegisterDevice(dbus::ObjectProxy* proxy,
-                               const std::string& client_id,
-                               const std::string& client_secret,
-                               const std::string& api_key) {
+bool CallManagerCheckDeviceRegistered(dbus::ObjectProxy* proxy) {
   dbus::MethodCall method_call(
-      buffet::dbus_constants::kManagerInterface,
-      buffet::dbus_constants::kManagerRegisterDeviceMethod);
-  dbus::MessageWriter writer(&method_call);
-  writer.AppendString(client_id);
-  writer.AppendString(client_secret);
-  writer.AppendString(api_key);
-  int timeout_ms = 1000;
+    buffet::dbus_constants::kManagerInterface,
+    buffet::dbus_constants::kManagerCheckDeviceRegistered);
+
   scoped_ptr<dbus::Response> response(
-      proxy->CallMethodAndBlock(&method_call, timeout_ms));
+    proxy->CallMethodAndBlock(&method_call, default_timeout_ms));
   if (!response) {
     std::cout << "Failed to receive a response." << std::endl;
     return false;
   }
 
   dbus::MessageReader reader(response.get());
-  std::string registration_id;
-  if (!reader.PopString(&registration_id)) {
-    std::cout << "No registration id in response." << std::endl;
+  std::string device_id;
+  if (!reader.PopString(&device_id)) {
+    std::cout << "No device ID in response." << std::endl;
     return false;
   }
 
-  std::cout << "Registration ID is " << registration_id << std::endl;
+  std::cout << "Device ID: "
+            << (device_id.empty() ? std::string("<unregistered>") : device_id)
+            << std::endl;
+  return true;
+}
+
+bool CallManagerGetDeviceInfo(dbus::ObjectProxy* proxy) {
+  dbus::MethodCall method_call(
+    buffet::dbus_constants::kManagerInterface,
+    buffet::dbus_constants::kManagerGetDeviceInfo);
+
+  scoped_ptr<dbus::Response> response(
+    proxy->CallMethodAndBlock(&method_call, default_timeout_ms));
+  if (!response) {
+    std::cout << "Failed to receive a response." << std::endl;
+    return false;
+  }
+
+  dbus::MessageReader reader(response.get());
+  std::string device_info;
+  if (!reader.PopString(&device_info)) {
+    std::cout << "No device info in response." << std::endl;
+    return false;
+  }
+
+  std::cout << "Device Info: "
+    << (device_info.empty() ? std::string("<unregistered>") : device_info)
+    << std::endl;
+  return true;
+}
+
+bool CallManagerStartRegisterDevice(
+    dbus::ObjectProxy* proxy,
+    const std::map<std::string, std::shared_ptr<base::Value>>& params) {
+  dbus::MethodCall method_call(
+      buffet::dbus_constants::kManagerInterface,
+      buffet::dbus_constants::kManagerStartRegisterDevice);
+  dbus::MessageWriter writer(&method_call);
+  dbus::MessageWriter dict_writer(nullptr);
+  writer.OpenArray("{sv}", &dict_writer);
+  for (auto&& pair : params) {
+    dbus::MessageWriter dict_entry_writer(nullptr);
+    dict_writer.OpenDictEntry(&dict_entry_writer);
+    dict_entry_writer.AppendString(pair.first);
+    dbus::AppendBasicTypeValueDataAsVariant(&dict_entry_writer,
+                                            *pair.second.get());
+    dict_writer.CloseContainer(&dict_entry_writer);
+  }
+  writer.CloseContainer(&dict_writer);
+
+  static const int timeout_ms = 3000;
+  scoped_ptr<dbus::Response> response(
+    proxy->CallMethodAndBlock(&method_call, timeout_ms));
+  if (!response) {
+    std::cout << "Failed to receive a response." << std::endl;
+    return false;
+  }
+
+  dbus::MessageReader reader(response.get());
+  std::string info;
+  if (!reader.PopString(&info)) {
+    std::cout << "No valid response." << std::endl;
+    return false;
+  }
+
+  std::cout << "Registration started: " << info << std::endl;
+  return true;
+}
+
+bool CallManagerFinishRegisterDevice(dbus::ObjectProxy* proxy,
+                                     const std::string& user_auth_code) {
+  dbus::MethodCall method_call(
+    buffet::dbus_constants::kManagerInterface,
+    buffet::dbus_constants::kManagerFinishRegisterDevice);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString(user_auth_code);
+  static const int timeout_ms = 10000;
+  scoped_ptr<dbus::Response> response(
+    proxy->CallMethodAndBlock(&method_call, timeout_ms));
+  if (!response) {
+    std::cout << "Failed to receive a response." << std::endl;
+    return false;
+  }
+
+  dbus::MessageReader reader(response.get());
+  std::string device_id;
+  if (!reader.PopString(&device_id)) {
+    std::cout << "No device ID in response." << std::endl;
+    return false;
+  }
+
+  std::cout << "Device ID is "
+            << (device_id.empty() ? std::string("<unregistered>") : device_id)
+            << std::endl;
   return true;
 }
 
@@ -78,9 +167,8 @@
       buffet::dbus_constants::kManagerUpdateStateMethod);
   dbus::MessageWriter writer(&method_call);
   writer.AppendString(json_blob);
-  int timeout_ms = 1000;
   scoped_ptr<dbus::Response> response(
-      proxy->CallMethodAndBlock(&method_call, timeout_ms));
+    proxy->CallMethodAndBlock(&method_call, default_timeout_ms));
   if (!response) {
     std::cout << "Failed to receive a response." << std::endl;
     return false;
@@ -91,8 +179,12 @@
 void usage() {
   std::cerr << "Possible commands:" << std::endl;
   std::cerr << "  " << kRootTestMethod << std::endl;
-  std::cerr << "  " << kManagerRegisterDeviceMethod
-            << "  " << " <client id> <client secret> <api key>" << std::endl;
+  std::cerr << "  " << kManagerCheckDeviceRegistered << std::endl;
+  std::cerr << "  " << kManagerGetDeviceInfo << std::endl;
+  std::cerr << "  " << kManagerStartRegisterDevice
+                    << " param1 = val1&param2 = val2..." << std::endl;
+  std::cerr << "  " << kManagerFinishRegisterDevice
+                    << " device_id" << std::endl;
   std::cerr << "  " << kManagerUpdateStateMethod << std::endl;
 }
 
@@ -107,39 +199,86 @@
   scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
 
   CommandLine::StringVector args = cl->GetArgs();
-  if (args.size() < 1) {
+  if (args.empty()) {
     usage();
     return EX_USAGE;
   }
 
   // Pop the command off of the args list.
-  std::string command = args[0];
+  std::string command = args.front();
   args.erase(args.begin());
   bool success = false;
   if (command.compare(kRootTestMethod) == 0) {
     auto proxy = GetBuffetDBusProxy(
         bus, buffet::dbus_constants::kRootServicePath);
     success = CallTestMethod(proxy);
-  } else if (command.compare(kManagerRegisterDeviceMethod) == 0) {
-    if (args.size() != 3) {
+  } else if (command.compare(kManagerCheckDeviceRegistered) == 0 ||
+             command.compare("cr") == 0) {
+    if (!args.empty()) {
       std::cerr << "Invalid number of arguments for "
-                << "Manager.RegisterDevice" << std::endl;
+        << "Manager." << kManagerCheckDeviceRegistered << std::endl;
+      usage();
+      return EX_USAGE;
+    }
+    auto proxy = GetBuffetDBusProxy(
+      bus, buffet::dbus_constants::kManagerServicePath);
+    success = CallManagerCheckDeviceRegistered(proxy);
+  } else if (command.compare(kManagerGetDeviceInfo) == 0 ||
+             command.compare("di") == 0) {
+    if (!args.empty()) {
+      std::cerr << "Invalid number of arguments for "
+        << "Manager." << kManagerGetDeviceInfo << std::endl;
+      usage();
+      return EX_USAGE;
+    }
+    auto proxy = GetBuffetDBusProxy(
+      bus, buffet::dbus_constants::kManagerServicePath);
+    success = CallManagerGetDeviceInfo(proxy);
+  } else if (command.compare(kManagerStartRegisterDevice) == 0 ||
+             command.compare("sr") == 0) {
+    if (args.size() > 1) {
+      std::cerr << "Invalid number of arguments for "
+                << "Manager." << kManagerStartRegisterDevice << std::endl;
       usage();
       return EX_USAGE;
     }
     auto proxy = GetBuffetDBusProxy(
         bus, buffet::dbus_constants::kManagerServicePath);
-    success = CallManagerRegisterDevice(proxy, args[0], args[1], args[2]);
-  } else if (command.compare(kManagerUpdateStateMethod) == 0) {
+    std::map<std::string, std::shared_ptr<base::Value>> params;
+
+    if (!args.empty()) {
+      auto key_values = chromeos::data_encoding::WebParamsDecode(args.front());
+      for (auto&& pair : key_values) {
+        params.insert(std::make_pair(
+          pair.first, std::shared_ptr<base::Value>(
+              base::Value::CreateStringValue(pair.second))));
+      }
+    }
+
+    success = CallManagerStartRegisterDevice(proxy, params);
+  } else if (command.compare(kManagerFinishRegisterDevice) == 0 ||
+             command.compare("fr") == 0) {
+    if (args.size() > 1) {
+      std::cerr << "Invalid number of arguments for "
+                << "Manager." << kManagerFinishRegisterDevice << std::endl;
+      usage();
+      return EX_USAGE;
+    }
+    auto proxy = GetBuffetDBusProxy(
+        bus, buffet::dbus_constants::kManagerServicePath);
+    success = CallManagerFinishRegisterDevice(
+        proxy, !args.empty() ? args.front() : std::string());
+  } else if (command.compare(kManagerUpdateStateMethod) == 0 ||
+             command.compare("us") == 0) {
     if (args.size() != 1) {
       std::cerr << "Invalid number of arguments for "
-                << "Manager.UpdateState" << std::endl;
+                << "Manager." << kManagerUpdateStateMethod << std::endl;
       usage();
       return EX_USAGE;
     }
     auto proxy = GetBuffetDBusProxy(
         bus, buffet::dbus_constants::kManagerServicePath);
-    success = CallManagerUpdateState(proxy, args[0]);
+    success = CallManagerUpdateState(proxy, args.front());
   } else {
     std::cerr << "Unknown command: " << command << std::endl;
     usage();