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:
SampleHandler(weave::provider::TaskRunner * task_runner)59 SampleHandler(weave::provider::TaskRunner* task_runner)
60 : task_runner_{task_runner} {}
Register(weave::Device * device)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:
OnHelloCommand(const std::weak_ptr<weave::Command> & command)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
OnPingCommand(const std::weak_ptr<weave::Command> & command)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
OnCountdownCommand(const std::weak_ptr<weave::Command> & command)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
DoTick(const std::weak_ptr<weave::Command> & command,int seconds)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
main(int argc,char ** argv)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