Async RegisterDevice implementation

This allows to remove HttpClient::SendRequestAndBlock.

BUG:24267885
Change-Id: I9e2bea86108d3a683be98121d88c5ce97a6af91c
Reviewed-on: https://weave-review.googlesource.com/1292
Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/libweave/examples/ubuntu/curl_http_client.cc b/libweave/examples/ubuntu/curl_http_client.cc
index 1b1e21f..1d69ce5 100644
--- a/libweave/examples/ubuntu/curl_http_client.cc
+++ b/libweave/examples/ubuntu/curl_http_client.cc
@@ -16,9 +16,9 @@
 struct ResponseImpl : public provider::HttpClient::Response {
   int GetStatusCode() const override { return status; }
   std::string GetContentType() const override { return content_type; }
-  const std::string& GetData() const override { return data; }
+  std::string GetData() const override { return data; }
 
-  int status;
+  long status{0};
   std::string content_type;
   std::string data;
 };
diff --git a/libweave/examples/ubuntu/curl_http_client.h b/libweave/examples/ubuntu/curl_http_client.h
index 7d62b3d..8d41c36 100644
--- a/libweave/examples/ubuntu/curl_http_client.h
+++ b/libweave/examples/ubuntu/curl_http_client.h
@@ -24,11 +24,6 @@
  public:
   explicit CurlHttpClient(provider::TaskRunner* task_runner);
 
-  std::unique_ptr<Response> SendRequestAndBlock(const std::string& method,
-                                                const std::string& url,
-                                                const Headers& headers,
-                                                const std::string& data,
-                                                ErrorPtr* error) override;
   void SendRequest(const std::string& method,
                    const std::string& url,
                    const Headers& headers,
@@ -37,6 +32,12 @@
                    const ErrorCallback& error_callback) override;
 
  private:
+  std::unique_ptr<Response> SendRequestAndBlock(const std::string& method,
+                                                const std::string& url,
+                                                const Headers& headers,
+                                                const std::string& data,
+                                                ErrorPtr* error);
+
   void RunSuccessCallback(const SuccessCallback& success_callback,
                           std::unique_ptr<Response> response);
   void RunErrorCallback(const ErrorCallback& error_callback,
diff --git a/libweave/examples/ubuntu/event_http_client.cc b/libweave/examples/ubuntu/event_http_client.cc
index f81916c..742eef8 100644
--- a/libweave/examples/ubuntu/event_http_client.cc
+++ b/libweave/examples/ubuntu/event_http_client.cc
@@ -49,7 +49,7 @@
  public:
   int GetStatusCode() const override { return status; }
   std::string GetContentType() const override { return content_type; }
-  const std::string& GetData() const { return data; }
+  std::string GetData() const { return data; }
 
   int status;
   std::string content_type;
@@ -61,7 +61,7 @@
   std::unique_ptr<evhttp_uri, EventDeleter> http_uri_;
   std::unique_ptr<evhttp_connection, EventDeleter> evcon_;
   HttpClient::SuccessCallback success_callback_;
-  HttpClient::ErrorCallback error_callback_;
+  ErrorCallback error_callback_;
 };
 
 void RequestDoneCallback(evhttp_request* req, void* ctx) {
@@ -93,15 +93,6 @@
 EventHttpClient::EventHttpClient(EventTaskRunner* task_runner)
     : task_runner_{task_runner} {}
 
-std::unique_ptr<provider::HttpClient::Response>
-EventHttpClient::SendRequestAndBlock(const std::string& method,
-                                     const std::string& url,
-                                     const Headers& headers,
-                                     const std::string& data,
-                                     ErrorPtr* error) {
-  return nullptr;
-}
-
 void EventHttpClient::SendRequest(const std::string& method,
                                   const std::string& url,
                                   const Headers& headers,
diff --git a/libweave/examples/ubuntu/event_http_client.h b/libweave/examples/ubuntu/event_http_client.h
index c38ad2e..53a01ab 100644
--- a/libweave/examples/ubuntu/event_http_client.h
+++ b/libweave/examples/ubuntu/event_http_client.h
@@ -20,11 +20,6 @@
  public:
   explicit EventHttpClient(EventTaskRunner* task_runner);
 
-  std::unique_ptr<Response> SendRequestAndBlock(const std::string& method,
-                                                const std::string& url,
-                                                const Headers& headers,
-                                                const std::string& data,
-                                                ErrorPtr* error) override;
   void SendRequest(const std::string& method,
                    const std::string& url,
                    const Headers& headers,
diff --git a/libweave/include/weave/provider/http_client.h b/libweave/include/weave/provider/http_client.h
index cfc8937..995e7d6 100644
--- a/libweave/include/weave/provider/http_client.h
+++ b/libweave/include/weave/provider/http_client.h
@@ -21,23 +21,13 @@
    public:
     virtual int GetStatusCode() const = 0;
     virtual std::string GetContentType() const = 0;
-    virtual const std::string& GetData() const = 0;
+    virtual std::string GetData() const = 0;
 
-    // TODO(vitalybuka): Hide when SendRequestAndBlock is removed.
     virtual ~Response() = default;
   };
 
   using Headers = std::vector<std::pair<std::string, std::string>>;
   using SuccessCallback = base::Callback<void(const Response&)>;
-  using ErrorCallback = base::Callback<void(const Error*)>;
-
-  // TODO(vitalybuka): Remove blocking version.
-  virtual std::unique_ptr<Response> SendRequestAndBlock(
-      const std::string& method,
-      const std::string& url,
-      const Headers& headers,
-      const std::string& data,
-      ErrorPtr* error) = 0;
 
   virtual void SendRequest(const std::string& method,
                            const std::string& url,
diff --git a/libweave/include/weave/provider/test/mock_http_client.h b/libweave/include/weave/provider/test/mock_http_client.h
index 86aca46..ce3bfc3 100644
--- a/libweave/include/weave/provider/test/mock_http_client.h
+++ b/libweave/include/weave/provider/test/mock_http_client.h
@@ -20,7 +20,7 @@
  public:
   MOCK_CONST_METHOD0(GetStatusCode, int());
   MOCK_CONST_METHOD0(GetContentType, std::string());
-  MOCK_CONST_METHOD0(GetData, const std::string&());
+  MOCK_CONST_METHOD0(GetData, std::string());
 };
 
 class MockHttpClient : public HttpClient {
@@ -34,12 +34,6 @@
                          const std::string&,
                          ErrorPtr*));
 
-  std::unique_ptr<Response> SendRequestAndBlock(const std::string& method,
-                                                const std::string& url,
-                                                const Headers& headers,
-                                                const std::string& data,
-                                                ErrorPtr* error) override;
-
   void SendRequest(const std::string& method,
                    const std::string& url,
                    const Headers& headers,
diff --git a/libweave/src/device_registration_info.cc b/libweave/src/device_registration_info.cc
index 8975c19..7960b77 100644
--- a/libweave/src/device_registration_info.cc
+++ b/libweave/src/device_registration_info.cc
@@ -118,14 +118,8 @@
                 HttpClient* transport)
       : method_{method}, url_{url}, transport_{transport} {}
 
-  std::unique_ptr<provider::HttpClient::Response> SendAndBlock(
-      ErrorPtr* error) {
-    return transport_->SendRequestAndBlock(method_, url_, GetFullHeaders(),
-                                           data_, error);
-  }
-
   void Send(const HttpClient::SuccessCallback& success_callback,
-            const HttpClient::ErrorCallback& error_callback) {
+            const ErrorCallback& error_callback) {
     static int debug_id = 0;
     ++debug_id;
     VLOG(1) << "Sending request. id:" << debug_id << " method:" << method_
@@ -139,8 +133,7 @@
       VLOG(2) << "Response data: " << response.GetData();
       success_callback.Run(response);
     };
-    auto on_error = [](int debug_id,
-                       const HttpClient::ErrorCallback& error_callback,
+    auto on_error = [](int debug_id, const ErrorCallback& error_callback,
                        const Error* error) {
       VLOG(1) << "Request failed, id=" << debug_id
               << ", reason: " << error->GetCode()
@@ -543,22 +536,35 @@
                  error_callback);
 }
 
+struct DeviceRegistrationInfo::RegisterCallbacks {
+  RegisterCallbacks(const SuccessCallback& success, const ErrorCallback& error)
+      : success_callback{success}, error_callback{error} {}
+  SuccessCallback success_callback;
+  ErrorCallback error_callback;
+};
+
+void DeviceRegistrationInfo::RegisterDeviceError(
+    const std::shared_ptr<RegisterCallbacks>& callbacks,
+    const Error* error) {
+  ErrorPtr error_clone = error->Clone();
+  task_runner_->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(callbacks->error_callback, base::Owned(error_clone.release())),
+      {});
+}
+
 void DeviceRegistrationInfo::RegisterDevice(
     const std::string& ticket_id,
     const SuccessCallback& success_callback,
     const ErrorCallback& error_callback) {
+  auto callbacks =
+      std::make_shared<RegisterCallbacks>(success_callback, error_callback);
+
   ErrorPtr error;
-
-  auto on_error = [this, &error_callback](ErrorPtr error) {
-    task_runner_->PostDelayedTask(
-        FROM_HERE, base::Bind(error_callback, base::Owned(error.release())),
-        {});
-  };
-
   std::unique_ptr<base::DictionaryValue> device_draft =
       BuildDeviceResource(&error);
   if (!device_draft)
-    return on_error(std::move(error));
+    return RegisterDeviceError(callbacks, error.get());
 
   base::DictionaryValue req_json;
   req_json.SetString("id", ticket_id);
@@ -570,29 +576,46 @@
 
   RequestSender sender{http::kPatch, url, http_client_};
   sender.SetJsonData(req_json);
-  auto response = sender.SendAndBlock(&error);
+  sender.Send(base::Bind(&DeviceRegistrationInfo::RegisterDeviceOnTicketSent,
+                         weak_factory_.GetWeakPtr(), ticket_id, callbacks),
+              base::Bind(&DeviceRegistrationInfo::RegisterDeviceError,
+                         weak_factory_.GetWeakPtr(), callbacks));
+}
 
-  if (!response)
-    return on_error(std::move(error));
-  auto json_resp = ParseJsonResponse(*response, &error);
+void DeviceRegistrationInfo::RegisterDeviceOnTicketSent(
+    const std::string& ticket_id,
+    const std::shared_ptr<RegisterCallbacks>& callbacks,
+    const provider::HttpClient::Response& response) {
+  ErrorPtr error;
+  auto json_resp = ParseJsonResponse(response, &error);
   if (!json_resp)
-    return on_error(std::move(error));
-  if (!IsSuccessful(*response)) {
+    return RegisterDeviceError(callbacks, error.get());
+
+  if (!IsSuccessful(response)) {
     ParseGCDError(json_resp.get(), &error);
-    return on_error(std::move(error));
+    return RegisterDeviceError(callbacks, error.get());
   }
 
-  url = GetServiceURL("registrationTickets/" + ticket_id + "/finalize",
-                      {{"key", GetSettings().api_key}});
-  response = RequestSender{http::kPost, url, http_client_}.SendAndBlock(&error);
-  if (!response)
-    return on_error(std::move(error));
-  json_resp = ParseJsonResponse(*response, &error);
+  std::string url =
+      GetServiceURL("registrationTickets/" + ticket_id + "/finalize",
+                    {{"key", GetSettings().api_key}});
+  RequestSender{http::kPost, url, http_client_}.Send(
+      base::Bind(&DeviceRegistrationInfo::RegisterDeviceOnTicketFinalized,
+                 weak_factory_.GetWeakPtr(), callbacks),
+      base::Bind(&DeviceRegistrationInfo::RegisterDeviceError,
+                 weak_factory_.GetWeakPtr(), callbacks));
+}
+
+void DeviceRegistrationInfo::RegisterDeviceOnTicketFinalized(
+    const std::shared_ptr<RegisterCallbacks>& callbacks,
+    const provider::HttpClient::Response& response) {
+  ErrorPtr error;
+  auto json_resp = ParseJsonResponse(response, &error);
   if (!json_resp)
-    return on_error(std::move(error));
-  if (!IsSuccessful(*response)) {
+    return RegisterDeviceError(callbacks, error.get());
+  if (!IsSuccessful(response)) {
     ParseGCDError(json_resp.get(), &error);
-    return on_error(std::move(error));
+    return RegisterDeviceError(callbacks, error.get());
   }
 
   std::string auth_code;
@@ -605,7 +628,7 @@
       !device_draft_response->GetString("id", &cloud_id)) {
     Error::AddTo(&error, FROM_HERE, kErrorDomainGCD, "unexpected_response",
                  "Device account missing in response");
-    return on_error(std::move(error));
+    return RegisterDeviceError(callbacks, error.get());
   }
 
   UpdateDeviceInfoTimestamp(*device_draft_response);
@@ -619,12 +642,20 @@
        {"redirect_uri", "oob"},
        {"scope", "https://www.googleapis.com/auth/clouddevices"},
        {"grant_type", "authorization_code"}});
-  response = sender2.SendAndBlock(&error);
+  sender2.Send(base::Bind(&DeviceRegistrationInfo::RegisterDeviceOnAuthCodeSent,
+                          weak_factory_.GetWeakPtr(), cloud_id, robot_account,
+                          callbacks),
+               base::Bind(&DeviceRegistrationInfo::RegisterDeviceError,
+                          weak_factory_.GetWeakPtr(), callbacks));
+}
 
-  if (!response)
-    return on_error(std::move(error));
-
-  json_resp = ParseOAuthResponse(*response, &error);
+void DeviceRegistrationInfo::RegisterDeviceOnAuthCodeSent(
+    const std::string& cloud_id,
+    const std::string& robot_account,
+    const std::shared_ptr<RegisterCallbacks>& callbacks,
+    const provider::HttpClient::Response& response) {
+  ErrorPtr error;
+  auto json_resp = ParseOAuthResponse(response, &error);
   int expires_in = 0;
   std::string refresh_token;
   if (!json_resp || !json_resp->GetString("access_token", &access_token_) ||
@@ -633,7 +664,7 @@
       access_token_.empty() || refresh_token.empty() || expires_in <= 0) {
     Error::AddTo(&error, FROM_HERE, kErrorDomainGCD, "unexpected_response",
                  "Device access_token missing in response");
-    return on_error(std::move(error));
+    return RegisterDeviceError(callbacks, error.get());
   }
 
   access_token_expiration_ =
@@ -645,7 +676,7 @@
   change.set_refresh_token(refresh_token);
   change.Commit();
 
-  task_runner_->PostDelayedTask(FROM_HERE, success_callback, {});
+  task_runner_->PostDelayedTask(FROM_HERE, callbacks->success_callback, {});
 
   StartNotificationChannel();
 
diff --git a/libweave/src/device_registration_info.h b/libweave/src/device_registration_info.h
index 74bf3a8..fdc4dcd 100644
--- a/libweave/src/device_registration_info.h
+++ b/libweave/src/device_registration_info.h
@@ -275,6 +275,22 @@
   // Wipes out the device registration information and stops server connections.
   void MarkDeviceUnregistered();
 
+  class RegisterCallbacks;
+  void RegisterDeviceError(const std::shared_ptr<RegisterCallbacks>& callbacks,
+                           const Error* error);
+  void RegisterDeviceOnTicketSent(
+      const std::string& ticket_id,
+      const std::shared_ptr<RegisterCallbacks>& callbacks,
+      const provider::HttpClient::Response& response);
+  void RegisterDeviceOnTicketFinalized(
+      const std::shared_ptr<RegisterCallbacks>& callbacks,
+      const provider::HttpClient::Response& response);
+  void RegisterDeviceOnAuthCodeSent(
+      const std::string& cloud_id,
+      const std::string& robot_account,
+      const std::shared_ptr<RegisterCallbacks>& callbacks,
+      const provider::HttpClient::Response& response);
+
   // Transient data
   std::string access_token_;
   base::Time access_token_expiration_;
diff --git a/libweave/src/device_registration_info_unittest.cc b/libweave/src/device_registration_info_unittest.cc
index 5245458..4a47013 100644
--- a/libweave/src/device_registration_info_unittest.cc
+++ b/libweave/src/device_registration_info_unittest.cc
@@ -91,7 +91,7 @@
       .WillRepeatedly(Return(http::kJsonUtf8));
   EXPECT_CALL(*response, GetData())
       .Times(AtLeast(1))
-      .WillRepeatedly(ReturnRefOfCopy(text));
+      .WillRepeatedly(Return(text));
   return response;
 }
 
diff --git a/libweave/src/test/mock_http_client.cc b/libweave/src/test/mock_http_client.cc
index 94cbe08..c3ffbef 100644
--- a/libweave/src/test/mock_http_client.cc
+++ b/libweave/src/test/mock_http_client.cc
@@ -11,16 +11,6 @@
 namespace provider {
 namespace test {
 
-std::unique_ptr<HttpClient::Response> MockHttpClient::SendRequestAndBlock(
-    const std::string& method,
-    const std::string& url,
-    const Headers& headers,
-    const std::string& data,
-    ErrorPtr* error) {
-  return std::unique_ptr<Response>{
-      MockSendRequest(method, url, headers, data, error)};
-}
-
 void MockHttpClient::SendRequest(const std::string& method,
                                  const std::string& url,
                                  const Headers& headers,
diff --git a/libweave/src/weave_unittest.cc b/libweave/src/weave_unittest.cc
index 69250fd..5334e6a 100644
--- a/libweave/src/weave_unittest.cc
+++ b/libweave/src/weave_unittest.cc
@@ -151,7 +151,7 @@
               .WillRepeatedly(Return("application/json; charset=utf-8"));
           EXPECT_CALL(*response, GetData())
               .Times(AtLeast(1))
-              .WillRepeatedly(ReturnRefOfCopy(json_response));
+              .WillRepeatedly(Return(json_response));
           return response;
         }));
   }