buffet: Implement a tool to do periodic polling.

Add a tool which will allow to run the given task forever
with the given delay between executions.

BUG=chromium:420604
TEST=cros_workon_make buffet --test&&manual

Change-Id: I0ec2cb4c8ba8df60009470b784cae8e66c8c3de6
Reviewed-on: https://chromium-review.googlesource.com/224972
Reviewed-by: Anton Muhin <antonm@chromium.org>
Commit-Queue: Anton Muhin <antonm@chromium.org>
Tested-by: Anton Muhin <antonm@chromium.org>
diff --git a/buffet/device_registration_info.cc b/buffet/device_registration_info.cc
index 8dd78a3..00fdecf 100644
--- a/buffet/device_registration_info.cc
+++ b/buffet/device_registration_info.cc
@@ -478,6 +478,14 @@
       FROM_HERE, base::Bind(cb, base::Owned(value.release())));
 }
 
+void PostRepeatingTask(const tracked_objects::Location& from_here,
+                       base::Closure task,
+                       base::TimeDelta delay) {
+  task.Run();
+  base::MessageLoop::current()->PostDelayedTask(
+      from_here, base::Bind(&PostRepeatingTask, from_here, task, delay), delay);
+}
+
 // TODO(antonm): May belong to chromeos/http.
 
 void SendRequestAsync(
@@ -504,8 +512,7 @@
                          num_retries - 1,
                          callback, errorback);
       };
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE, base::Bind(c));
+      base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(c));
     } else {
       PostToCallback(errorback, std::move(error));
     }
@@ -645,7 +652,7 @@
 
   const std::string command_queue_url{
     GetServiceURL("commands/queue", {{"deviceId", device_id_}})};
-  auto fetch_commands_cb = [command_queue_url, std_errorback]
+  auto fetch_commands = [command_queue_url, std_errorback]
       (DeviceRegistrationInfo* self,
        CloudRequestCallback callback, const base::DictionaryValue&) {
     self->DoCloudRequest(chromeos::http::request_type::kGet,
@@ -654,7 +661,8 @@
                          callback, std_errorback);
   };
 
-  auto abort_commands_cb = [] (const base::DictionaryValue& json) {
+  auto abort_commands = [](base::Callback<void(void)> callback,
+                           const base::DictionaryValue& json) {
     const base::ListValue* commands{nullptr};
     if (json.GetList("commands", &commands)) {
       const size_t size{commands->GetSize()};
@@ -683,19 +691,25 @@
         // TODO(antonm): Really abort the command.
       }
     }
+    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  };
+
+  auto delay = base::TimeDelta::FromSeconds(7);
+  auto poll_commands = [delay](DeviceRegistrationInfo* self) {
+    PostRepeatingTask(FROM_HERE, base::Bind([](){
+      VLOG(1) << "Poll commands";
+      // TODO(antonm): Implement real polling of commands.
+    }), delay);
   };
 
   base::Bind(update_device_resource,
              base::Unretained(this),
              base::Owned(device_resource.release()),
-             base::Bind(fetch_commands_cb,
+             base::Bind(fetch_commands,
                         base::Unretained(this),
-                        base::Bind(abort_commands_cb))).Run();
-
-
-  // TODO(antonm): Implement the rest of startup sequence:
-  //   * Poll for commands to run
-  //   * Schedule periodic polling
+                        base::Bind(abort_commands,
+                                   base::Bind(poll_commands,
+                                              base::Unretained(this))))).Run();
 }
 
 }  // namespace buffet