blob: 5016b0b750ce0508115439642ed83204ff7902a2 [file] [log] [blame]
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This is a sample daemon that "handles" Buffet commands.
// It just prints the information about the command received to stdout and
// marks the command as processed.
#include <string>
#include <sysexits.h>
#include <base/bind.h>
#include <base/command_line.h>
#include <base/format_macros.h>
#include <base/json/json_writer.h>
#include <base/values.h>
#include <chromeos/daemons/dbus_daemon.h>
#include <chromeos/map_utils.h>
#include <chromeos/strings/string_utils.h>
#include <chromeos/syslog_logging.h>
#include "buffet/dbus-proxies.h"
namespace {
std::unique_ptr<base::DictionaryValue> DictionaryToJson(
const chromeos::VariantDictionary& dictionary);
std::unique_ptr<base::Value> AnyToJson(const chromeos::Any& value) {
if (value.IsTypeCompatible<chromeos::VariantDictionary>())
return DictionaryToJson(value.Get<chromeos::VariantDictionary>());
if (value.IsTypeCompatible<std::string>()) {
return std::unique_ptr<base::Value>{
new base::StringValue(value.Get<std::string>())};
}
if (value.IsTypeCompatible<double>()) {
return std::unique_ptr<base::Value>{
new base::FundamentalValue(value.Get<double>())};
}
if (value.IsTypeCompatible<bool>()) {
return std::unique_ptr<base::Value>{
new base::FundamentalValue(value.Get<bool>())};
}
if (value.IsTypeCompatible<int>()) {
return std::unique_ptr<base::Value>{
new base::FundamentalValue(value.Get<int>())};
}
LOG(FATAL) << "Unsupported type:" << value.GetType().name();
return {};
}
std::unique_ptr<base::DictionaryValue> DictionaryToJson(
const chromeos::VariantDictionary& dictionary) {
std::unique_ptr<base::DictionaryValue> result{new base::DictionaryValue};
for (const auto& it : dictionary)
result->Set(it.first, AnyToJson(it.second).release());
return result;
}
std::string DictionaryToString(const chromeos::VariantDictionary& dictionary) {
std::unique_ptr<base::DictionaryValue> json{DictionaryToJson(dictionary)};
std::string str;
base::JSONWriter::Write(*json, &str);
return str;
}
} // anonymous namespace
class Daemon final : public chromeos::DBusDaemon {
public:
Daemon() = default;
protected:
int OnInit() override;
void OnShutdown(int* return_code) override;
private:
std::unique_ptr<com::android::Weave::ObjectManagerProxy> object_manager_;
void OnBuffetCommand(com::android::Weave::CommandProxy* command);
void OnBuffetCommandRemoved(const dbus::ObjectPath& object_path);
void OnPropertyChange(com::android::Weave::CommandProxy* command,
const std::string& property_name);
void OnCommandProgress(com::android::Weave::CommandProxy* command,
int progress);
DISALLOW_COPY_AND_ASSIGN(Daemon);
};
int Daemon::OnInit() {
int return_code = chromeos::DBusDaemon::OnInit();
if (return_code != EX_OK)
return return_code;
object_manager_.reset(new com::android::Weave::ObjectManagerProxy{bus_});
object_manager_->SetCommandAddedCallback(
base::Bind(&Daemon::OnBuffetCommand, base::Unretained(this)));
object_manager_->SetCommandRemovedCallback(
base::Bind(&Daemon::OnBuffetCommandRemoved, base::Unretained(this)));
printf("Waiting for commands...\n");
return EX_OK;
}
void Daemon::OnShutdown(int* return_code) {
printf("Shutting down...\n");
}
void Daemon::OnPropertyChange(com::android::Weave::CommandProxy* command,
const std::string& property_name) {
printf("Notification: property '%s' on command '%s' changed.\n",
property_name.c_str(), command->id().c_str());
printf(" Current command status: '%s'\n", command->status().c_str());
std::string progress = DictionaryToString(command->progress());
printf(" Current command progress: %s\n", progress.c_str());
std::string results = DictionaryToString(command->results());
printf(" Current command results: %s\n", results.c_str());
}
void Daemon::OnBuffetCommand(com::android::Weave::CommandProxy* command) {
// "Handle" only commands that belong to this daemon's category.
if (command->status() == "done")
return;
command->SetPropertyChangedCallback(base::Bind(&Daemon::OnPropertyChange,
base::Unretained(this)));
printf("++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("Command received: %s\n", command->name().c_str());
printf("DBus Object Path: %s\n", command->GetObjectPath().value().c_str());
printf(" ID: %s\n", command->id().c_str());
printf(" status: %s\n", command->status().c_str());
printf(" origin: %s\n", command->origin().c_str());
std::string param_names = DictionaryToString(command->parameters());
printf(" parameters: %s\n", param_names.c_str());
OnCommandProgress(command, 0);
}
void Daemon::OnCommandProgress(com::android::Weave::CommandProxy* command,
int progress) {
printf("Updating command '%s' progress to %d%%\n", command->id().c_str(),
progress);
auto new_progress = command->progress();
new_progress["progress"] = progress;
command->SetProgress(new_progress, nullptr);
if (progress >= 100) {
command->Done(nullptr);
} else {
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE, base::Bind(&Daemon::OnCommandProgress,
base::Unretained(this), command, progress + 10),
base::TimeDelta::FromSeconds(1));
}
}
void Daemon::OnBuffetCommandRemoved(const dbus::ObjectPath& object_path) {
printf("------------------------------------------------\n");
printf("Command removed\n");
printf("DBus Object Path: %s\n", object_path.value().c_str());
}
int main(int argc, char* argv[]) {
base::CommandLine::Init(argc, argv);
chromeos::InitLog(chromeos::kLogToSyslog |
chromeos::kLogToStderr |
chromeos::kLogHeader);
Daemon daemon;
return daemon.Run();
}