| // 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. | 
 |  | 
 | #include "components/autofill_assistant/browser/retry_timer.h" | 
 |  | 
 | #include <algorithm> | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/bind_helpers.h" | 
 | #include "base/numerics/clamped_math.h" | 
 | #include "components/autofill_assistant/browser/client_status.h" | 
 |  | 
 | namespace autofill_assistant { | 
 |  | 
 | RetryTimer::RetryTimer(base::TimeDelta period) : period_(period) {} | 
 | RetryTimer::~RetryTimer() = default; | 
 |  | 
 | void RetryTimer::Start( | 
 |     base::TimeDelta max_wait_time, | 
 |     base::RepeatingCallback<void(base::OnceCallback<void(const ClientStatus&)>)> | 
 |         task, | 
 |     base::OnceCallback<void(const ClientStatus&)> on_done) { | 
 |   Reset(); | 
 |   task_ = std::move(task); | 
 |   on_done_ = std::move(on_done); | 
 |   remaining_attempts_ = base::ClampFloor<int64_t>( | 
 |       std::max(0.0, max_wait_time.FltDiv(period_)) + 1.0); | 
 |   RunTask(); | 
 | } | 
 |  | 
 | void RetryTimer::Cancel() { | 
 |   if (!on_done_) | 
 |     return; | 
 |  | 
 |   Reset(); | 
 | } | 
 |  | 
 | void RetryTimer::Reset() { | 
 |   timer_.reset(); | 
 |   task_id_++;  // cancels any pending OnTaskDone callbacks | 
 |   task_.Reset(); | 
 |   on_done_.Reset(); | 
 | } | 
 |  | 
 | void RetryTimer::RunTask() { | 
 |   task_.Run(base::BindOnce(&RetryTimer::OnTaskDone, | 
 |                            weak_ptr_factory_.GetWeakPtr(), task_id_)); | 
 | } | 
 |  | 
 | void RetryTimer::OnTaskDone(int64_t task_id, const ClientStatus& status) { | 
 |   if (task_id != task_id_)  // Ignore callbacks from cancelled tasks | 
 |     return; | 
 |  | 
 |   remaining_attempts_--; | 
 |   if (status.ok() || remaining_attempts_ <= 0) { | 
 |     CHECK_GE(remaining_attempts_, 0); | 
 |     task_.Reset();  // release any resources held by the callback | 
 |     std::move(on_done_).Run(status); | 
 |     // Don't do anything after calling on_done_, as it could have deleted this. | 
 |     return; | 
 |   } | 
 |   timer_ = std::make_unique<base::OneShotTimer>(); | 
 |   timer_->Start(FROM_HERE, period_, | 
 |                 base::BindOnce(&RetryTimer::RunTask, | 
 |                                // Safe, since timer_ is owned by this instance | 
 |                                base::Unretained(this))); | 
 | } | 
 |  | 
 | }  // namespace autofill_assistant |