blob: 905a977d62507a0af5cf38138d4880f165dbaaa1 [file] [log] [blame]
// 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;
}