| // 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 |