blob: 4f747ec9faaae54129a129819c10f9da866a1a2f [file] [log] [blame]
// 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 "components/feed/core/v2/public/ntp_feed_content_fetcher.h"
#include <memory>
#include "components/feed/core/proto/v2/wire/client_info.pb.h"
#include "components/feed/core/proto/v2/wire/stream_structure.pb.h"
#include "components/feed/core/v2/feed_network_impl.h"
#include "components/feed/core/v2/proto_util.h"
#include "components/feed/feed_feature_list.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
namespace feed {
namespace {
constexpr int kTargetArticleCount = 3;
void HandleWebFeedListContentsResponse(
base::OnceCallback<void(std::vector<NtpFeedContentFetcher::Article>)>
callback,
FeedNetwork::ApiResult<feedwire::Response> response) {
std::vector<NtpFeedContentFetcher::Article> result;
if (!response.response_body) {
DLOG(ERROR) << "Failed to fetch content for feed NTP module. Status: "
<< response.response_info.status_code;
return std::move(callback).Run(std::move(result));
}
// Get the first several articles from the response. No attempt is made
// to show a variety of publishers.
for (const feedwire::DataOperation& data_operation :
response.response_body->feed_response().data_operation()) {
if (data_operation.operation() !=
feedwire::DataOperation::UPDATE_OR_APPEND ||
!data_operation.has_feature() ||
!data_operation.feature().has_content()) {
continue;
}
for (const feedwire::PrefetchMetadata& prefetch_metadata :
data_operation.feature().content().prefetch_metadata()) {
auto& article = result.emplace_back();
article.title = prefetch_metadata.title();
article.publisher = prefetch_metadata.publisher();
article.url = GURL(prefetch_metadata.uri());
article.thumbnail_url = GURL(prefetch_metadata.image_url());
article.favicon_url = GURL(prefetch_metadata.favicon_url());
if (result.size() >= kTargetArticleCount)
return std::move(callback).Run(std::move(result));
}
}
DLOG_IF(ERROR, result.size() < kTargetArticleCount)
<< "Request for content for the feed NTP module succeeded but the "
"response contained fewer than "
<< kTargetArticleCount << " articles.";
std::move(callback).Run(std::move(result));
}
} // namespace
NtpFeedContentFetcher::NtpFeedContentFetcher(
signin::IdentityManager* identity_manager,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& api_key,
PrefService* pref_service)
: feed_network_delegate_(identity_manager) {
feed_network_ = std::make_unique<FeedNetworkImpl>(
&feed_network_delegate_, identity_manager, api_key, url_loader_factory,
pref_service);
}
NtpFeedContentFetcher::~NtpFeedContentFetcher() = default;
NtpFeedContentFetcher::Article::Article() = default;
NtpFeedContentFetcher::Article::Article(const Article&) = default;
NtpFeedContentFetcher::Article::~Article() = default;
void NtpFeedContentFetcher::FetchFollowingFeedArticles(
base::OnceCallback<void(std::vector<NtpFeedContentFetcher::Article>)>
callback) {
feedwire::Request request = CreateFeedQueryRefreshRequest(
StreamType(StreamKind::kFollowing),
feedwire::FeedQuery::INTERACTIVE_WEB_FEED, RequestMetadata(),
/*consistency_token=*/std::string(), SingleWebFeedEntryPoint::kOther,
/*doc_view_counts=*/{});
feedwire::ClientInfo* client_info =
request.mutable_feed_request()->mutable_client_info();
// TODO(https://crbug.com/1328951): For the desktop feed prototype we call the
// Android endpoint and need to pretend we are an Android client. This won't
// be the case for the launch.
client_info->set_platform_type(feedwire::ClientInfo::ANDROID_ID);
client_info->set_app_type(feedwire::ClientInfo::CHROME_ANDROID);
// For the prototype, it's okay if the request fails or the user is signed
// out; the module will be empty.
feed_network_->SendApiRequest<WebFeedListContentsDiscoverApi>(
request, feed_network_delegate_.GetAccountInfo(), RequestMetadata(),
base::BindOnce(&HandleWebFeedListContentsResponse, std::move(callback)));
}
void NtpFeedContentFetcher::SetFeedNetworkForTesting(
std::unique_ptr<FeedNetwork> feed_network) {
feed_network_ = std::move(feed_network);
}
NtpFeedContentFetcher::NetworkDelegate::NetworkDelegate(
signin::IdentityManager* identity_manager)
: identity_manager_(identity_manager) {}
std::string NtpFeedContentFetcher::NetworkDelegate::GetLanguageTag() {
// TODO(https://crbug.com/1328951): Change this for the final implementation.
return std::string();
}
AccountInfo NtpFeedContentFetcher::NetworkDelegate::GetAccountInfo() {
return AccountInfo(identity_manager_->GetPrimaryAccountInfo(
GetConsentLevelNeededForPersonalizedFeed()));
}
bool NtpFeedContentFetcher::NetworkDelegate::IsOffline() {
// TODO(https://crbug.com/1328951): Change this for the final implementation.
return false;
}
} // namespace feed