chromium/ash/system/time/calendar_event_fetch.cc

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

#include "ash/system/time/calendar_event_fetch.h"

#include "ash/calendar/calendar_client.h"
#include "ash/calendar/calendar_controller.h"
#include "ash/glanceables/post_login_glanceables_metrics_recorder.h"
#include "ash/shell.h"
#include "ash/system/time/calendar_metrics.h"
#include "ash/system/time/calendar_utils.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "google_apis/calendar/calendar_api_requests.h"

#undef ENABLED_VLOG_LEVEL
#define ENABLED_VLOG_LEVEL 1

namespace ash {

CalendarEventFetch::CalendarEventFetch(
    const base::Time& start_of_month,
    FetchCompleteCallback complete_callback,
    FetchInternalErrorCallback internal_error_callback,
    const base::TickClock* tick_clock)
    : start_of_month_(start_of_month),
      time_range_(calendar_utils::GetFetchStartEndTimes(start_of_month)),
      complete_callback_(std::move(complete_callback)),
      internal_error_callback_(std::move(internal_error_callback)),
      fetch_start_time_(base::TimeTicks::Now()),
      timeout_(tick_clock),
      calendar_id_(google_apis::calendar::kPrimaryCalendarId) {
  SendFetchRequest();
  Shell::Get()
      ->post_login_glanceables_metrics_reporter()
      ->RecordCalendarFetch();
}

CalendarEventFetch::CalendarEventFetch(
    const base::Time& start_of_month,
    FetchCompleteCallback complete_callback,
    FetchInternalErrorCallback internal_error_callback,
    const base::TickClock* tick_clock,
    const std::string& calendar_id,
    const std::string& calendar_color_id)
    : start_of_month_(start_of_month),
      time_range_(calendar_utils::GetFetchStartEndTimes(start_of_month)),
      complete_callback_(std::move(complete_callback)),
      internal_error_callback_(std::move(internal_error_callback)),
      fetch_start_time_(base::TimeTicks::Now()),
      timeout_(tick_clock),
      calendar_id_(calendar_id),
      calendar_color_id_(calendar_color_id) {
  SendFetchRequestByCalendarId();
  Shell::Get()
      ->post_login_glanceables_metrics_reporter()
      ->RecordCalendarFetch();
}

CalendarEventFetch::~CalendarEventFetch() = default;

void CalendarEventFetch::Cancel() {
  std::move(cancel_closure_).Run();
}

void CalendarEventFetch::SendFetchRequest() {
  if (cancel_closure_)
    Cancel();

  CalendarClient* client = Shell::Get()->calendar_controller()->GetClient();
  CHECK(client);

  cancel_closure_ =
      client->GetEventList(base::BindOnce(&CalendarEventFetch::OnResultReceived,
                                          weak_factory_.GetWeakPtr()),
                           time_range_.first, time_range_.second);
  CHECK(cancel_closure_);

  timeout_.Start(FROM_HERE, calendar_utils::kCalendarDataFetchTimeout,
                 base::BindOnce(&CalendarEventFetch::OnTimeout,
                                weak_factory_.GetWeakPtr()));
}

void CalendarEventFetch::SendFetchRequestByCalendarId() {
  if (cancel_closure_) {
    Cancel();
  }

  CalendarClient* client = Shell::Get()->calendar_controller()->GetClient();
  CHECK(client);

  cancel_closure_ = client->GetEventList(
      base::BindOnce(&CalendarEventFetch::OnResultReceived,
                     weak_factory_.GetWeakPtr()),
      time_range_.first, time_range_.second, calendar_id_, calendar_color_id_);
  CHECK(cancel_closure_);

  timeout_.Start(FROM_HERE, calendar_utils::kCalendarDataFetchTimeout,
                 base::BindOnce(&CalendarEventFetch::OnTimeout,
                                weak_factory_.GetWeakPtr()));
}

void CalendarEventFetch::OnResultReceived(
    google_apis::ApiErrorCode error,
    std::unique_ptr<google_apis::calendar::EventList> events) {
  // Cancel timeout timer.
  timeout_.Stop();

  calendar_metrics::RecordEventListFetchDuration(base::TimeTicks::Now() -
                                                 fetch_start_time_);
  calendar_metrics::RecordEventListFetchTimeout(false);

  // IMPORTANT: 'this' is NOT safe to use after `complete_callback_` has been
  // executed, as the last thing it does is destroy its
  // std::unique_ptr<CalendarEventFetch> to this object.
  std::move(complete_callback_)
      .Run(start_of_month_, calendar_id_, error, events.get());
}

void CalendarEventFetch::OnTimeout() {
  calendar_metrics::RecordEventListFetchTimeout(true);

  // IMPORTANT: 'this' is NOT safe to use after `internal_error_callback_` has
  // been executed, as the last thing it does is destroy its
  // std::unique_ptr<CalendarEventFetch> to this object.
  std::move(internal_error_callback_)
      .Run(start_of_month_, calendar_id_,
           CalendarEventFetchInternalErrorCode::kTimeout);
}

}  // namespace ash