chromium/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h

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

#ifndef CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_
#define CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_

#include <optional>
#include <string>

#include "base/containers/queue.h"
#include "base/functional/callback.h"
#include "third_party/nearby/sharing/proto/device_rpc.pb.h"
#include "third_party/nearby/sharing/proto/rpc_resources.pb.h"

// Manages a queue of data needed to make UpdateDevice RPC requests to the
// Nearby Server. Implementations should make the actual HTTP calls by
// overriding HandleNextRequest(), which is invoked when the next request is
// ready to be run. Implementations should call FinishAttempt() with the result
// of the attempt and possibly the response.
//
// NOTE: We do *not* support upload of the device name. This field of the proto
// appears to be a relic of the old Nearby Share model. Upload of the field
// could be a privacy concern that we want to avoid.
//
// TODO(crbug.com/1105547): Instead of queuing requests, hold a single pending
// request and update the fields as other UpdateDeviceData() call are made.
// Then, queue up all of callbacks from the merged requests in the Request
// struct; invoke the callback in the order they were added. This will reduce
// the number of UpdateDevice RPC calls.
class NearbyShareDeviceDataUpdater {
 public:
  // If the request is unsuccessful, |response| is std::nullopt.
  using ResultCallback = base::OnceCallback<void(
      const std::optional<nearby::sharing::proto::UpdateDeviceResponse>&
          response)>;

  struct Request {
    Request(
        std::optional<std::vector<nearby::sharing::proto::Contact>> contacts,
        std::optional<std::vector<nearby::sharing::proto::PublicCertificate>>
            certificates,
        ResultCallback callback);
    Request(Request&& request);
    Request& operator=(Request&& request);
    Request(const Request&) = delete;
    Request& operator=(const Request&) = delete;
    ~Request();

    std::optional<std::vector<nearby::sharing::proto::Contact>> contacts;
    std::optional<std::vector<nearby::sharing::proto::PublicCertificate>>
        certificates;
    ResultCallback callback;
  };

  // |device_id|: The ID used by the Nearby server to differentiate multiple
  //              devices from the same account.
  explicit NearbyShareDeviceDataUpdater(const std::string& device_id);

  virtual ~NearbyShareDeviceDataUpdater();

  // Queue up an UpdateDevice RPC request to update the following fields on the
  // Nearby server if the parameter is not std::nullopt:
  //
  // |contacts|: The list of contacts that the Nearby server will send
  //             all-contacts-visibility certificates to. Contacts marked
  //             is_selected will be sent selected-contacts-visibility
  //             certificates.
  //
  // |certificates|: The local device's certificates that the Nearby server will
  //                 distribute to the appropriate |contacts|.
  //
  // If only the UpdateDevice RPC response data is desired, set all
  // aforementioned parameters to std::nullopt.
  void UpdateDeviceData(
      std::optional<std::vector<nearby::sharing::proto::Contact>> contacts,
      std::optional<std::vector<nearby::sharing::proto::PublicCertificate>>
          certificates,
      ResultCallback callback);

 protected:
  void ProcessRequestQueue();
  virtual void HandleNextRequest() = 0;

  // If the request is unsuccessful, |response| is std::nullopt.
  void FinishAttempt(
      const std::optional<nearby::sharing::proto::UpdateDeviceResponse>&
          response);

  std::string device_id_;
  bool is_request_in_progress_ = false;
  base::queue<Request> pending_requests_;
};

#endif  // CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_DEVICE_DATA_UPDATER_H_