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