examples/daemon: split daemon into seperate binaries

Also introducing helpers for the daemon argument parsing and
constructions.

Change-Id: I4b4438785eb7322ede1d16409e6f057d037a66e5
Reviewed-on: https://weave-review.googlesource.com/1442
Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/examples/daemon/sample/daemon.gyp b/examples/daemon/sample/daemon.gyp
new file mode 100644
index 0000000..29d8235
--- /dev/null
+++ b/examples/daemon/sample/daemon.gyp
@@ -0,0 +1,18 @@
+# Copyright 2015 The Weave Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'weave_daemon_sample',
+      'type': 'executable',
+      'sources': [
+        'sample.cc',
+      ],
+      'dependencies': [
+        '<@(DEPTH)/libweave_standalone.gyp:libweave',
+        '<@(DEPTH)/examples/provider/provider.gyp:libweave_provider',
+      ]
+    }
+  ]
+}
diff --git a/examples/daemon/sample/sample.cc b/examples/daemon/sample/sample.cc
new file mode 100644
index 0000000..905a977
--- /dev/null
+++ b/examples/daemon/sample/sample.cc
@@ -0,0 +1,167 @@
+// Copyright 2015 The Weave 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 "examples/daemon/common/daemon.h"
+
+#include <weave/device.h>
+#include <weave/provider/task_runner.h>
+
+#include <base/bind.h>
+#include <base/memory/weak_ptr.h>
+
+// SampleHandler is a command handler example.
+// It implements the following commands:
+// - _hello: handle a command with an argument and set its results.
+// - _ping: update device state.
+// - _countdown: handle long running command and report progress.
+class SampleHandler {
+ public:
+  SampleHandler(weave::provider::TaskRunner* task_runner)
+      : task_runner_{task_runner} {}
+  void Register(weave::Device* device) {
+    device_ = device;
+
+    device->AddCommandDefinitionsFromJson(R"({
+      "_sample": {
+        "_hello": {
+          "minimalRole": "user",
+          "parameters": {
+            "_name": "string"
+          },
+          "results": { "_reply": "string" }
+        },
+        "_ping": {
+          "minimalRole": "user",
+          "results": {}
+        },
+        "_countdown": {
+          "minimalRole": "user",
+          "parameters": {
+            "_seconds": {"minimum": 1, "maximum": 25}
+          },
+          "progress": { "_seconds_left": "integer"},
+          "results": {}
+        }
+      }
+    })");
+
+    device->AddStateDefinitionsFromJson(R"({
+      "_sample": {"_ping_count":"integer"}
+    })");
+
+    device->SetStatePropertiesFromJson(R"({
+      "_sample": {"_ping_count": 0}
+    })",
+                                       nullptr);
+
+    device->AddCommandHandler("_sample._hello",
+                              base::Bind(&SampleHandler::OnHelloCommand,
+                                         weak_ptr_factory_.GetWeakPtr()));
+    device->AddCommandHandler("_sample._ping",
+                              base::Bind(&SampleHandler::OnPingCommand,
+                                         weak_ptr_factory_.GetWeakPtr()));
+    device->AddCommandHandler("_sample._countdown",
+                              base::Bind(&SampleHandler::OnCountdownCommand,
+                                         weak_ptr_factory_.GetWeakPtr()));
+  }
+
+ private:
+  void OnHelloCommand(const std::weak_ptr<weave::Command>& command) {
+    auto cmd = command.lock();
+    if (!cmd)
+      return;
+    LOG(INFO) << "received command: " << cmd->GetName();
+
+    std::string name;
+    if (!cmd->GetParameters()->GetString("_name", &name)) {
+      weave::ErrorPtr error;
+      weave::Error::AddTo(&error, FROM_HERE, "example",
+                          "invalid_parameter_value", "Name is missing");
+      cmd->Abort(error.get(), nullptr);
+      return;
+    }
+
+    base::DictionaryValue result;
+    result.SetString("_reply", "Hello " + name);
+    cmd->Complete(result, nullptr);
+    LOG(INFO) << cmd->GetName() << " command finished: " << result;
+  }
+
+  void OnPingCommand(const std::weak_ptr<weave::Command>& command) {
+    auto cmd = command.lock();
+    if (!cmd)
+      return;
+    LOG(INFO) << "received command: " << cmd->GetName();
+
+    base::DictionaryValue state;
+    state.SetInteger("_sample._ping_count", ++ping_count_);
+    device_->SetStateProperties(state, nullptr);
+    LOG(INFO) << "New state: " << *device_->GetState();
+
+    base::DictionaryValue result;
+    cmd->Complete(result, nullptr);
+
+    LOG(INFO) << cmd->GetName() << " command finished: " << result;
+  }
+
+  void OnCountdownCommand(const std::weak_ptr<weave::Command>& command) {
+    auto cmd = command.lock();
+    if (!cmd)
+      return;
+    LOG(INFO) << "received command: " << cmd->GetName();
+
+    int seconds;
+    if (!cmd->GetParameters()->GetInteger("_seconds", &seconds))
+      seconds = 10;
+
+    LOG(INFO) << "starting countdown";
+    DoTick(cmd, seconds);
+  }
+
+  void DoTick(const std::weak_ptr<weave::Command>& command, int seconds) {
+    auto cmd = command.lock();
+    if (!cmd)
+      return;
+
+    if (seconds > 0) {
+      std::string todo;
+      cmd->GetParameters()->GetString("_todo", &todo);
+      LOG(INFO) << "countdown tick: " << seconds << " seconds left";
+
+      base::DictionaryValue progress;
+      progress.SetInteger("_seconds_left", seconds);
+      cmd->SetProgress(progress, nullptr);
+      task_runner_->PostDelayedTask(
+          FROM_HERE,
+          base::Bind(&SampleHandler::DoTick, weak_ptr_factory_.GetWeakPtr(),
+                     command, --seconds),
+          base::TimeDelta::FromSeconds(1));
+      return;
+    }
+
+    base::DictionaryValue result;
+    cmd->Complete(result, nullptr);
+    LOG(INFO) << "countdown finished";
+    LOG(INFO) << cmd->GetName() << " command finished: " << result;
+  }
+
+  weave::Device* device_{nullptr};
+  weave::provider::TaskRunner* task_runner_{nullptr};
+
+  int ping_count_{0};
+  base::WeakPtrFactory<SampleHandler> weak_ptr_factory_{this};
+};
+
+int main(int argc, char** argv) {
+  Daemon::Options opts;
+  if (!opts.Parse(argc, argv)) {
+    Daemon::Options::ShowUsage(argv[0]);
+    return 1;
+  }
+  Daemon daemon{opts};
+  SampleHandler handler{daemon.GetTaskRunner()};
+  handler.Register(daemon.GetDevice());
+  daemon.Run();
+  return 0;
+}