Home | History | Annotate | Download | only in sample
      1 // Copyright 2015 The Weave Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "examples/daemon/common/daemon.h"
      6 
      7 #include <weave/device.h>
      8 #include <weave/provider/task_runner.h>
      9 
     10 #include <base/bind.h>
     11 #include <base/memory/weak_ptr.h>
     12 
     13 namespace {
     14 
     15 const char kTraits[] = R"({
     16   "_sample": {
     17     "commands": {
     18       "hello": {
     19         "minimalRole": "user",
     20         "parameters": {
     21           "name": { "type": "string" }
     22         },
     23         "results": {
     24           "reply": { "type": "string" }
     25         }
     26       },
     27       "ping": {
     28         "minimalRole": "user",
     29         "parameters": {}
     30       },
     31       "countdown": {
     32         "minimalRole": "user",
     33         "parameters": {
     34           "seconds": {
     35             "type": "integer",
     36             "minimum": 1,
     37             "maximum": 25
     38           }
     39         }
     40       }
     41     },
     42     "state": {
     43       "pingCount": { "type": "integer" }
     44     }
     45   }
     46 })";
     47 
     48 const char kComponent[] = "sample";
     49 
     50 }  // anonymous namespace
     51 
     52 // SampleHandler is a command handler example.
     53 // It implements the following commands:
     54 // - _hello: handle a command with an argument and set its results.
     55 // - _ping: update device state.
     56 // - _countdown: handle long running command and report progress.
     57 class SampleHandler {
     58  public:
     59   SampleHandler(weave::provider::TaskRunner* task_runner)
     60       : task_runner_{task_runner} {}
     61   void Register(weave::Device* device) {
     62     device_ = device;
     63 
     64     device->AddTraitDefinitionsFromJson(kTraits);
     65     CHECK(device->AddComponent(kComponent, {"_sample"}, nullptr));
     66     CHECK(device->SetStatePropertiesFromJson(
     67         kComponent, R"({"_sample": {"pingCount": 0}})", nullptr));
     68 
     69     device->AddCommandHandler(kComponent, "_sample.hello",
     70                               base::Bind(&SampleHandler::OnHelloCommand,
     71                                          weak_ptr_factory_.GetWeakPtr()));
     72     device->AddCommandHandler(kComponent, "_sample.ping",
     73                               base::Bind(&SampleHandler::OnPingCommand,
     74                                          weak_ptr_factory_.GetWeakPtr()));
     75     device->AddCommandHandler(kComponent, "_sample.countdown",
     76                               base::Bind(&SampleHandler::OnCountdownCommand,
     77                                          weak_ptr_factory_.GetWeakPtr()));
     78   }
     79 
     80  private:
     81   void OnHelloCommand(const std::weak_ptr<weave::Command>& command) {
     82     auto cmd = command.lock();
     83     if (!cmd)
     84       return;
     85     LOG(INFO) << "received command: " << cmd->GetName();
     86 
     87     const auto& params = cmd->GetParameters();
     88     std::string name;
     89     if (!params.GetString("name", &name)) {
     90       weave::ErrorPtr error;
     91       weave::Error::AddTo(&error, FROM_HERE, "invalid_parameter_value",
     92                           "Name is missing");
     93       cmd->Abort(error.get(), nullptr);
     94       return;
     95     }
     96 
     97     base::DictionaryValue result;
     98     result.SetString("reply", "Hello " + name);
     99     cmd->Complete(result, nullptr);
    100     LOG(INFO) << cmd->GetName() << " command finished: " << result;
    101   }
    102 
    103   void OnPingCommand(const std::weak_ptr<weave::Command>& command) {
    104     auto cmd = command.lock();
    105     if (!cmd)
    106       return;
    107     LOG(INFO) << "received command: " << cmd->GetName();
    108 
    109     device_->SetStateProperty(kComponent, "_sample.pingCount",
    110                               base::FundamentalValue{++ping_count_}, nullptr);
    111     LOG(INFO) << "New component state: " << device_->GetComponents();
    112 
    113     cmd->Complete({}, nullptr);
    114 
    115     LOG(INFO) << cmd->GetName() << " command finished";
    116   }
    117 
    118   void OnCountdownCommand(const std::weak_ptr<weave::Command>& command) {
    119     auto cmd = command.lock();
    120     if (!cmd)
    121       return;
    122     LOG(INFO) << "received command: " << cmd->GetName();
    123 
    124     const auto& params = cmd->GetParameters();
    125     int seconds;
    126     if (!params.GetInteger("seconds", &seconds))
    127       seconds = 10;
    128 
    129     LOG(INFO) << "starting countdown";
    130     DoTick(cmd, seconds);
    131   }
    132 
    133   void DoTick(const std::weak_ptr<weave::Command>& command, int seconds) {
    134     auto cmd = command.lock();
    135     if (!cmd)
    136       return;
    137 
    138     if (seconds > 0) {
    139       LOG(INFO) << "countdown tick: " << seconds << " seconds left";
    140       base::DictionaryValue progress;
    141       progress.SetInteger("seconds_left", seconds);
    142       cmd->SetProgress(progress, nullptr);
    143       task_runner_->PostDelayedTask(
    144           FROM_HERE,
    145           base::Bind(&SampleHandler::DoTick, weak_ptr_factory_.GetWeakPtr(),
    146                      command, --seconds),
    147           base::TimeDelta::FromSeconds(1));
    148       return;
    149     }
    150 
    151     cmd->Complete({}, nullptr);
    152     LOG(INFO) << "countdown finished";
    153     LOG(INFO) << cmd->GetName() << " command finished";
    154   }
    155 
    156   weave::Device* device_{nullptr};
    157   weave::provider::TaskRunner* task_runner_{nullptr};
    158 
    159   int ping_count_{0};
    160   base::WeakPtrFactory<SampleHandler> weak_ptr_factory_{this};
    161 };
    162 
    163 int main(int argc, char** argv) {
    164   Daemon::Options opts;
    165   if (!opts.Parse(argc, argv)) {
    166     Daemon::Options::ShowUsage(argv[0]);
    167     return 1;
    168   }
    169   Daemon daemon{opts};
    170   SampleHandler handler{daemon.GetTaskRunner()};
    171   handler.Register(daemon.GetDevice());
    172   daemon.Run();
    173   return 0;
    174 }
    175