blob: 0373723de1701819aac0638d80d19acd2463792b [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "dockyard_proxy_grpc.h"
#include <zircon/status.h>
#include <chrono>
#include <memory>
#include <string>
#include "dockyard_proxy.h"
#include "garnet/lib/system_monitor/protos/dockyard.grpc.pb.h"
#include "src/lib/fxl/logging.h"
namespace harvester {
namespace {
constexpr DockyardProxyStatus ToDockyardProxyStatus(
const grpc::Status& status) {
return status.ok() ? DockyardProxyStatus::OK : DockyardProxyStatus::ERROR;
}
} // namespace
DockyardProxyStatus DockyardProxyGrpc::Init() {
dockyard_proto::InitRequest request;
request.set_device_name("TODO SET DEVICE NAME");
request.set_version(dockyard::DOCKYARD_VERSION);
auto now = std::chrono::system_clock::now();
uint64_t nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(
now.time_since_epoch())
.count();
request.set_device_time_ns(nanoseconds);
dockyard_proto::InitReply reply;
grpc::ClientContext context;
grpc::Status status = stub_->Init(&context, request, &reply);
if (status.ok()) {
return DockyardProxyStatus::OK;
}
FXL_LOG(ERROR) << status.error_code() << ": " << status.error_message();
FXL_LOG(ERROR) << "Unable to send to dockyard.";
return DockyardProxyStatus::ERROR;
}
DockyardProxyStatus DockyardProxyGrpc::SendInspectJson(
const std::string& dockyard_path, const std::string& json) {
auto now = std::chrono::system_clock::now();
uint64_t nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(
now.time_since_epoch())
.count();
dockyard::DockyardId dockyard_id;
grpc::Status status = GetDockyardIdForPath(&dockyard_id, dockyard_path);
if (status.ok()) {
return ToDockyardProxyStatus(
SendInspectJsonById(nanoseconds, dockyard_id, json));
}
return ToDockyardProxyStatus(status);
}
DockyardProxyStatus DockyardProxyGrpc::SendSample(
const std::string& dockyard_path, uint64_t value) {
// TODO(smbug.com/35): system_clock might be at usec resolution. Consider
// using high_resolution_clock.
auto now = std::chrono::system_clock::now();
uint64_t nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(
now.time_since_epoch())
.count();
dockyard::DockyardId dockyard_id;
grpc::Status status = GetDockyardIdForPath(&dockyard_id, dockyard_path);
if (status.ok()) {
return ToDockyardProxyStatus(
SendSampleById(nanoseconds, dockyard_id, value));
}
return ToDockyardProxyStatus(status);
}
DockyardProxyStatus DockyardProxyGrpc::SendSampleList(const SampleList list) {
// TODO(smbug.com/35): system_clock might be at usec resolution. Consider
// using high_resolution_clock.
auto now = std::chrono::system_clock::now();
uint64_t nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(
now.time_since_epoch())
.count();
SampleListById by_id(list.size());
auto path_iter = list.begin();
auto id_iter = by_id.begin();
for (; path_iter != list.end(); ++path_iter, ++id_iter) {
dockyard::DockyardId dockyard_id;
grpc::Status status = GetDockyardIdForPath(&dockyard_id, path_iter->first);
if (!status.ok()) {
return ToDockyardProxyStatus(status);
}
id_iter->first = dockyard_id;
id_iter->second = path_iter->second;
}
return ToDockyardProxyStatus(SendSampleListById(nanoseconds, by_id));
}
DockyardProxyStatus DockyardProxyGrpc::SendStringSampleList(
const StringSampleList list) {
// TODO(smbug.com/35): system_clock might be at usec resolution. Consider
// using high_resolution_clock.
auto now = std::chrono::system_clock::now();
uint64_t nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(
now.time_since_epoch())
.count();
std::vector<dockyard::DockyardId> dockyard_ids;
std::vector<const std::string*> dockyard_strings;
for (const auto& element : list) {
// Both the key (first) and value (second) are strings. Get IDs for each.
dockyard_strings.emplace_back(&element.first);
dockyard_strings.emplace_back(&element.second);
}
// Get an ID for each string (path or otherwise). The ID will then be used to
// in place of the strings.
GetDockyardIdsForPaths(&dockyard_ids, dockyard_strings);
SampleListById by_id;
auto ids_iter = dockyard_ids.begin();
for (size_t i = 0; i < list.size(); ++i) {
dockyard::DockyardId path_id = *ids_iter++;
dockyard::DockyardId value_id = *ids_iter++;
by_id.emplace_back(path_id, value_id);
}
return ToDockyardProxyStatus(SendSampleListById(nanoseconds, by_id));
}
grpc::Status DockyardProxyGrpc::SendInspectJsonById(
uint64_t time, dockyard::DockyardId dockyard_id, const std::string& json) {
// Data we are sending to the server.
dockyard_proto::InspectJson inspect;
inspect.set_time(time);
inspect.set_dockyard_id(dockyard_id);
inspect.set_json(json);
grpc::ClientContext context;
std::shared_ptr<grpc::ClientReaderWriter<dockyard_proto::InspectJson,
dockyard_proto::EmptyMessage>>
stream(stub_->SendInspectJson(&context));
stream->Write(inspect);
stream->WritesDone();
return stream->Finish();
}
grpc::Status DockyardProxyGrpc::SendSampleById(uint64_t time,
dockyard::DockyardId dockyard_id,
uint64_t value) {
// Data we are sending to the server.
dockyard_proto::RawSample sample;
sample.set_time(time);
sample.mutable_sample()->set_key(dockyard_id);
sample.mutable_sample()->set_value(value);
grpc::ClientContext context;
std::shared_ptr<grpc::ClientReaderWriter<dockyard_proto::RawSample,
dockyard_proto::EmptyMessage>>
stream(stub_->SendSample(&context));
stream->Write(sample);
stream->WritesDone();
return stream->Finish();
}
grpc::Status DockyardProxyGrpc::SendSampleListById(uint64_t time,
const SampleListById list) {
// Data we are sending to the server.
dockyard_proto::RawSamples samples;
samples.set_time(time);
for (auto iter = list.begin(); iter != list.end(); ++iter) {
auto sample = samples.add_sample();
sample->set_key(iter->first);
sample->set_value(iter->second);
}
grpc::ClientContext context;
std::shared_ptr<grpc::ClientReaderWriter<dockyard_proto::RawSamples,
dockyard_proto::EmptyMessage>>
stream(stub_->SendSamples(&context));
stream->Write(samples);
stream->WritesDone();
return stream->Finish();
}
grpc::Status DockyardProxyGrpc::GetDockyardIdForPath(
dockyard::DockyardId* dockyard_id, const std::string& dockyard_path) {
std::vector<dockyard::DockyardId> dockyard_ids;
std::vector<const std::string*> dockyard_paths = {&dockyard_path};
grpc::Status status = GetDockyardIdsForPaths(&dockyard_ids, dockyard_paths);
if (status.ok()) {
*dockyard_id = dockyard_ids[0];
}
return status;
}
grpc::Status DockyardProxyGrpc::GetDockyardIdsForPaths(
std::vector<dockyard::DockyardId>* dockyard_ids,
const std::vector<const std::string*>& dockyard_paths) {
dockyard_proto::DockyardPaths need_ids;
std::vector<size_t> indexes;
for (const auto& dockyard_path : dockyard_paths) {
auto iter = dockyard_path_to_id_.find(*dockyard_path);
if (iter != dockyard_path_to_id_.end()) {
dockyard_ids->emplace_back(iter->second);
} else {
need_ids.add_path(*dockyard_path);
indexes.emplace_back(dockyard_ids->size());
dockyard_ids->emplace_back(-1);
}
}
if (indexes.size() == 0) {
// All strings had cached IDs.
return grpc::Status::OK;
}
// Missing some IDs, request them from the Dockyard.
// Container for the data we expect from the server.
dockyard_proto::DockyardIds reply;
grpc::ClientContext context;
grpc::Status status =
stub_->GetDockyardIdsForPaths(&context, need_ids, &reply);
if (status.ok()) {
for (size_t index : indexes) {
dockyard::DockyardId dockyard_id = reply.id(index);
(*dockyard_ids)[index] = dockyard_id;
// Memoize it.
dockyard_path_to_id_.emplace(*dockyard_paths[index], dockyard_id);
}
}
return status;
}
} // namespace harvester