text: // Copyright 2019 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_SCHEDULER_H_
  #define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_SCHEDULER_H_
  
  #include <string>
  
  #include "base/memory/weak_ptr.h"
  #include "base/time/time.h"
  #include "chromeos/services/device_sync/cryptauth_device_sync_result.h"
  #include "chromeos/services/device_sync/cryptauth_enrollment_result.h"
  #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
  #include "third_party/abseil-cpp/absl/types/optional.h"
  
  namespace chromeos {
  
  namespace device_sync {
  
  // Schedules CryptAuth Enrollment and DeviceSync requests, alerting the
  // respective Enrollment or DeviceSync delegate when a request is due via
  // EnrollmentDelegate::OnEnrollmentRequest() or
  // DeviceSyncDelegate::OnDeviceSyncRequested(). Enrollment and DeviceSync
  // scheduling begins on StartEnrollmentScheduling() and
  // StartDeviceSyncScheduling(), respectively.
  //
  // The scheduler client can bypass the current schedule and trigger an
  // Enrollment/DeviceSync request via RequestEnrollment()/RequestDeviceSync().
  // When an Enrollment/DeviceSync attempt has completed--successfully or not--the
  // client should invoke HandleEnrollmentResult()/HandleDeviceSyncResult() so the
  // scheduler can process the attempt outcomes and schedule future attempts if
  // necessary.
  class CryptAuthScheduler {
   public:
    class EnrollmentDelegate {
     public:
      EnrollmentDelegate() = default;
      virtual ~EnrollmentDelegate() = default;
  
      // Called to alert the delegate that an Enrollment attempt has been
      // requested by the scheduler.
      //   |client_metadata|: Contains the retry count, invocation reason, and
      //       possible session ID of the Enrollment request.
      //   |client_directive_policy_reference|: Identifies the CryptAuth policy
      //       associated with the ClientDirective parameters used to schedule
      //       this Enrollment attempt. If no ClientDirective was used by the
      //       scheduler, absl::nullopt is passed.
      virtual void OnEnrollmentRequested(
          const cryptauthv2::ClientMetadata& client_metadata,
          const absl::optional<cryptauthv2::PolicyReference>&
              client_directive_policy_reference) = 0;
    };
  
    class DeviceSyncDelegate {
     public:
      DeviceSyncDelegate() = default;
      virtual ~DeviceSyncDelegate() = default;
  
      // Called to alert the delegate that a DeviceSync attempt has been requested
      // by the scheduler.
      //   |client_metadata|: Contains the retry count, invocation reason, and
      //       possible session ID of the DeviceSync request.
      virtual void OnDeviceSyncRequested(
          const cryptauthv2::ClientMetadata& client_metadata) = 0;
    };
  
    CryptAuthScheduler(const CryptAuthScheduler&) = delete;
    CryptAuthScheduler& operator=(const CryptAuthScheduler&) = delete;
  
    virtual ~CryptAuthScheduler();
  
    // Note: These should only be called once.
    void StartEnrollmentScheduling(
        const base::WeakPtr<EnrollmentDelegate>& enrollment_delegate);
    void StartDeviceSyncScheduling(
        const base::WeakPtr<DeviceSyncDelegate>& device_sync_delegate);
  
    bool HasEnrollmentSchedulingStarted();
    bool HasDeviceSyncSchedulingStarted();
  
    // Requests an Enrollment/DeviceSync with the desired |invocation_reason| and,
    // if relevant, the |session_id| of the GCM message that requested an
    // Enrollment/DeviceSync.
    virtual void RequestEnrollment(
        const cryptauthv2::ClientMetadata::InvocationReason& invocation_reason,
        const absl::optional<std::string>& session_id) = 0;
    virtual void RequestDeviceSync(
        const cryptauthv2::ClientMetadata::InvocationReason& invocation_reason,
        const absl::optional<std::string>& session_id) = 0;
  
    // Processes the result of the previous Enrollment/DeviceSync attempt.
    virtual void HandleEnrollmentResult(
        const CryptAuthEnrollmentResult& enrollment_result) = 0;
    virtual void HandleDeviceSyncResult(
        const CryptAuthDeviceSyncResult& device_sync_result) = 0;
  
    // Returns the time of the last known successful Enrollment/DeviceSync. If no
    // successful Enrollment/DeviceSync has occurred, absl::nullopt is returned.
    virtual absl::optional<base::Time> GetLastSuccessfulEnrollmentTime()
        const = 0;
    virtual absl::optional<base::Time> GetLastSuccessfulDeviceSyncTime()
        const = 0;
  
    // Returns the scheduler's time period between a successful Enrollment and its
    // next Enrollment request.
    virtual base::TimeDelta GetRefreshPeriod() const = 0;
  
    // Returns the time until the next scheduled Enrollment/DeviceSync request.
    // Returns null if there is no request scheduled.
    virtual absl::optional<base::TimeDelta> GetTimeToNextEnrollmentRequest()
        const = 0;
    virtual absl::optional<base::TimeDelta> GetTimeToNextDeviceSyncRequest()
        const = 0;
  
    // Returns true after the Enrollment/DeviceSync delegate has been alerted of a
    // request but before the delegate has returned the result to the scheduler.
    // In other words, between
    // {Enrollment,DeviceSync}Delegate::On{Enrollment,DeviceSync}Requested() and
    // Handle{Enrollment,DeviceSync}Result().
    virtual bool IsWaitingForEnrollmentResult() const = 0;
    virtual bool IsWaitingForDeviceSyncResult() const = 0;
  
    // The number of times the current Enrollment/DeviceSync request has failed.
    // Once the Enrollment/DeviceSync request succeeds or a fresh request is
    // made--for example, via a forced Enrollment/DeviceSync--this counter is
    // reset.
    virtual size_t GetNumConsecutiveEnrollmentFailures() const = 0;
    virtual size_t GetNumConsecutiveDeviceSyncFailures() const = 0;
  
   protected:
    CryptAuthScheduler();
  
    virtual void OnEnrollmentSchedulingStarted();
    virtual void OnDeviceSyncSchedulingStarted();
  
    // Alerts the Enrollment/DeviceSync delegate that an Enrollment/DeviceSync has
    // been requested.
    void NotifyEnrollmentRequested(
        const cryptauthv2::ClientMetadata& client_metadata,
        const absl::optional<cryptauthv2::PolicyReference>&
            client_directive_policy_reference) const;
    void NotifyDeviceSyncRequested(
        const cryptauthv2::ClientMetadata& client_metadata) const;
  
   private:
    base::WeakPtr<EnrollmentDelegate> enrollment_delegate_;
    base::WeakPtr<DeviceSyncDelegate> device_sync_delegate_;
  };
  
  }  // namespace device_sync
  
  }  // namespace chromeos
  
  #endif  // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_SCHEDULER_H_
  