blob: 7f4d112f54b074b2329f98c3c1a8b9b7152599a0 [file] [log] [blame]
// Copyright 2018 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/journey/journey_info_fetcher.h"
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "components/journey/journey_info_json_request.h"
#include "services/data_decoder/public/cpp/safe_json_parser.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace journey {
namespace {
const char kChromeSyncScope[] = "https://www.googleapis.com/auth/chromememex";
} // namespace
JourneyInfoFetcher::JourneyInfoFetcher(
identity::IdentityManager* identity_manager,
const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory)
: identity_manager_(identity_manager), loader_factory_(loader_factory) {}
JourneyInfoFetcher::~JourneyInfoFetcher() = default;
void JourneyInfoFetcher::FetchJourneyInfo(
std::vector<int64_t> timestamps,
FetchResponseAvailableCallback callback) {
if (!identity_manager_->HasPrimaryAccount()) {
FetchFinished(std::move(callback), /*result=*/nullptr,
"Primary Account is not Available. Sign in is required");
return;
}
pending_requests_.emplace(std::move(timestamps), std::move(callback));
RequestOAuthTokenService();
}
void JourneyInfoFetcher::RequestOAuthTokenService() {
if (token_fetcher_)
return;
OAuth2TokenService::ScopeSet scopes{kChromeSyncScope};
token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
"journey_info", identity_manager_, scopes,
base::BindOnce(&JourneyInfoFetcher::AccessTokenFetchFinished,
base::Unretained(this)),
identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
}
void JourneyInfoFetcher::AccessTokenFetchFinished(
GoogleServiceAuthError error,
identity::AccessTokenInfo access_token_info) {
DCHECK(token_fetcher_);
std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
token_fetcher_deleter(std::move(token_fetcher_));
if (error.state() != GoogleServiceAuthError::NONE) {
AccessTokenError(error);
return;
}
DCHECK(!access_token_info.token.empty());
while (!pending_requests_.empty()) {
std::pair<std::vector<int64_t>, FetchResponseAvailableCallback>
timestamp_and_callback = std::move(pending_requests_.front());
pending_requests_.pop();
StartRequest(timestamp_and_callback.first,
std::move(timestamp_and_callback.second),
access_token_info.token);
}
}
void JourneyInfoFetcher::AccessTokenError(const GoogleServiceAuthError& error) {
DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
DLOG(WARNING) << "JourneyInfoFetcher::AccessTokenError "
"Unable to get token: "
<< error.ToString();
while (!pending_requests_.empty()) {
std::pair<std::vector<int64_t>, FetchResponseAvailableCallback>
timestamp_and_callback = std::move(pending_requests_.front());
pending_requests_.pop();
FetchFinished(std::move(timestamp_and_callback.second), /*result=*/nullptr,
error.ToString());
}
}
void JourneyInfoFetcher::StartRequest(const std::vector<int64_t>& timestamps,
FetchResponseAvailableCallback callback,
const std::string& oauth_access_token) {
JourneyInfoJsonRequest::Builder builder;
builder.SetTimestamps(timestamps)
.SetAuthentication(
base::StringPrintf("bearer %s", oauth_access_token.c_str()))
.SetParseJsonCallback(base::BindRepeating(
&data_decoder::SafeJsonParser::Parse,
/*connector=*/nullptr)); // This is an Android-only component,
// connector is unused on Android.
auto json_request = builder.Build();
JourneyInfoJsonRequest* raw_request = json_request.get();
raw_request->Start(
base::BindOnce(&JourneyInfoFetcher::JsonRequestDone,
base::Unretained(this), std::move(json_request),
std::move(callback)),
loader_factory_);
}
const std::string& JourneyInfoFetcher::GetLastJsonForDebugging() const {
return last_fetch_json_;
}
void JourneyInfoFetcher::JsonRequestDone(
std::unique_ptr<JourneyInfoJsonRequest> request,
FetchResponseAvailableCallback callback,
std::unique_ptr<base::Value> result,
const std::string& error_detail) {
DCHECK(request);
last_fetch_json_ = request->GetResponseString();
FetchFinished(std::move(callback), std::move(result), error_detail);
}
void JourneyInfoFetcher::FetchFinished(FetchResponseAvailableCallback callback,
std::unique_ptr<base::Value> result,
const std::string& error_detail) {
DCHECK((result && !result->is_none()) || error_detail != "");
// Returned |result| can be empty while |error_detail| is "".
std::move(callback).Run(std::move(result), error_detail);
}
} // namespace journey