chromium/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.h"

#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "chrome/browser/nearby_sharing/client/nearby_share_client.h"
#include "third_party/nearby/sharing/proto/rpc_resources.pb.h"

namespace {

const char kDeviceIdPrefix[] = "users/me/devices/";
const char kContactsFieldMaskPath[] = "contacts";
const char kCertificatesFieldMaskPath[] = "public_certificates";

void RecordResultMetrics(ash::nearby::NearbyHttpResult result) {
  base::UmaHistogramEnumeration(
      "Nearby.Share.LocalDeviceData.DeviceDataUpdater.HttpResult", result);
}

}  // namespace

// static
NearbyShareDeviceDataUpdaterImpl::Factory*
    NearbyShareDeviceDataUpdaterImpl::Factory::test_factory_ = nullptr;

// static
std::unique_ptr<NearbyShareDeviceDataUpdater>
NearbyShareDeviceDataUpdaterImpl::Factory::Create(
    const std::string& device_id,
    base::TimeDelta timeout,
    NearbyShareClientFactory* client_factory) {
  if (test_factory_)
    return test_factory_->CreateInstance(device_id, timeout, client_factory);

  return base::WrapUnique(
      new NearbyShareDeviceDataUpdaterImpl(device_id, timeout, client_factory));
}

// static
void NearbyShareDeviceDataUpdaterImpl::Factory::SetFactoryForTesting(
    Factory* test_factory) {
  test_factory_ = test_factory;
}

NearbyShareDeviceDataUpdaterImpl::Factory::~Factory() = default;

NearbyShareDeviceDataUpdaterImpl::NearbyShareDeviceDataUpdaterImpl(
    const std::string& device_id,
    base::TimeDelta timeout,
    NearbyShareClientFactory* client_factory)
    : NearbyShareDeviceDataUpdater(device_id),
      timeout_(timeout),
      client_factory_(client_factory) {}

NearbyShareDeviceDataUpdaterImpl::~NearbyShareDeviceDataUpdaterImpl() = default;

void NearbyShareDeviceDataUpdaterImpl::HandleNextRequest() {
  timer_.Start(FROM_HERE, timeout_,
               base::BindOnce(&NearbyShareDeviceDataUpdaterImpl::OnTimeout,
                              base::Unretained(this)));

  nearby::sharing::proto::UpdateDeviceRequest request;
  request.mutable_device()->set_name(kDeviceIdPrefix + device_id_);
  if (pending_requests_.front().contacts) {
    *request.mutable_device()->mutable_contacts() = {
        pending_requests_.front().contacts->begin(),
        pending_requests_.front().contacts->end()};
    request.mutable_update_mask()->add_paths(kContactsFieldMaskPath);
  }
  if (pending_requests_.front().certificates) {
    *request.mutable_device()->mutable_public_certificates() = {
        pending_requests_.front().certificates->begin(),
        pending_requests_.front().certificates->end()};
    request.mutable_update_mask()->add_paths(kCertificatesFieldMaskPath);
  }

  client_ = client_factory_->CreateInstance();
  client_->UpdateDevice(
      request,
      base::BindOnce(&NearbyShareDeviceDataUpdaterImpl::OnRpcSuccess,
                     base::Unretained(this)),
      base::BindOnce(&NearbyShareDeviceDataUpdaterImpl::OnRpcFailure,
                     base::Unretained(this)));
}

void NearbyShareDeviceDataUpdaterImpl::OnRpcSuccess(
    const nearby::sharing::proto::UpdateDeviceResponse& response) {
  timer_.Stop();
  nearby::sharing::proto::UpdateDeviceResponse response_copy(response);
  client_.reset();
  RecordResultMetrics(ash::nearby::NearbyHttpResult::kSuccess);
  FinishAttempt(response_copy);
}

void NearbyShareDeviceDataUpdaterImpl::OnRpcFailure(
    ash::nearby::NearbyHttpError error) {
  timer_.Stop();
  client_.reset();
  RecordResultMetrics(ash::nearby::NearbyHttpErrorToResult(error));
  FinishAttempt(/*response=*/std::nullopt);
}

void NearbyShareDeviceDataUpdaterImpl::OnTimeout() {
  client_.reset();
  RecordResultMetrics(ash::nearby::NearbyHttpResult::kTimeout);
  FinishAttempt(/*response=*/std::nullopt);
}