Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/ntp_snippets/remote/remote_suggestions_fetcher.h" | 5 #include "components/ntp_snippets/remote/remote_suggestions_fetcher.h" |
| 6 | 6 |
| 7 #include <cstdlib> | 7 #include <cstdlib> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 129 } | 129 } |
| 130 return true; | 130 return true; |
| 131 } | 131 } |
| 132 | 132 |
| 133 // Creates suggestions from dictionary values in |list| and adds them to | 133 // Creates suggestions from dictionary values in |list| and adds them to |
| 134 // |suggestions|. Returns true on success, false if anything went wrong. | 134 // |suggestions|. Returns true on success, false if anything went wrong. |
| 135 // |remote_category_id| is only used if |content_suggestions_api| is true. | 135 // |remote_category_id| is only used if |content_suggestions_api| is true. |
| 136 bool AddSuggestionsFromListValue(bool content_suggestions_api, | 136 bool AddSuggestionsFromListValue(bool content_suggestions_api, |
| 137 int remote_category_id, | 137 int remote_category_id, |
| 138 const base::ListValue& list, | 138 const base::ListValue& list, |
| 139 RemoteSuggestion::PtrVector* suggestions) { | 139 RemoteSuggestion::PtrVector* suggestions, |
| 140 const base::Time& fetch_time) { | |
| 140 for (const auto& value : list) { | 141 for (const auto& value : list) { |
| 141 const base::DictionaryValue* dict = nullptr; | 142 const base::DictionaryValue* dict = nullptr; |
| 142 if (!value->GetAsDictionary(&dict)) { | 143 if (!value->GetAsDictionary(&dict)) { |
| 143 return false; | 144 return false; |
| 144 } | 145 } |
| 145 | 146 |
| 146 std::unique_ptr<RemoteSuggestion> suggestion; | 147 std::unique_ptr<RemoteSuggestion> suggestion; |
| 147 if (content_suggestions_api) { | 148 if (content_suggestions_api) { |
| 148 suggestion = RemoteSuggestion::CreateFromContentSuggestionsDictionary( | 149 suggestion = RemoteSuggestion::CreateFromContentSuggestionsDictionary( |
| 149 *dict, remote_category_id); | 150 *dict, remote_category_id, fetch_time); |
| 150 } else { | 151 } else { |
| 151 suggestion = RemoteSuggestion::CreateFromChromeReaderDictionary(*dict); | 152 suggestion = |
| 153 RemoteSuggestion::CreateFromChromeReaderDictionary(*dict, fetch_time); | |
| 152 } | 154 } |
| 153 if (!suggestion) { | 155 if (!suggestion) { |
| 154 return false; | 156 return false; |
| 155 } | 157 } |
| 156 | 158 |
| 157 suggestions->push_back(std::move(suggestion)); | 159 suggestions->push_back(std::move(suggestion)); |
| 158 } | 160 } |
| 159 return true; | 161 return true; |
| 160 } | 162 } |
| 161 | 163 |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 435 StartTokenRequest(); | 437 StartTokenRequest(); |
| 436 } | 438 } |
| 437 | 439 |
| 438 void RemoteSuggestionsFetcher::JsonRequestDone( | 440 void RemoteSuggestionsFetcher::JsonRequestDone( |
| 439 std::unique_ptr<JsonRequest> request, | 441 std::unique_ptr<JsonRequest> request, |
| 440 SnippetsAvailableCallback callback, | 442 SnippetsAvailableCallback callback, |
| 441 std::unique_ptr<base::Value> result, | 443 std::unique_ptr<base::Value> result, |
| 442 FetchResult status_code, | 444 FetchResult status_code, |
| 443 const std::string& error_details) { | 445 const std::string& error_details) { |
| 444 DCHECK(request); | 446 DCHECK(request); |
| 447 // Record the time when request for fetching remote content snippets finished. | |
| 448 const base::Time fetch_time = base::Time::FromInternalValue( | |
| 449 tick_clock_->NowTicks().ToInternalValue()); | |
|
Marc Treib
2017/02/13 10:24:49
Hrm, this is a bit ugly, and I'm not entirely conv
markusheintz_
2017/02/13 11:19:16
I share your concerns and I fully agree. I'm actua
| |
| 450 | |
| 445 last_fetch_json_ = request->GetResponseString(); | 451 last_fetch_json_ = request->GetResponseString(); |
| 446 | 452 |
| 447 UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", | 453 UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", |
| 448 request->GetFetchDuration()); | 454 request->GetFetchDuration()); |
| 449 | 455 |
| 450 if (!result) { | 456 if (!result) { |
| 451 FetchFinished(OptionalFetchedCategories(), std::move(callback), status_code, | 457 FetchFinished(OptionalFetchedCategories(), std::move(callback), status_code, |
| 452 error_details); | 458 error_details); |
| 453 return; | 459 return; |
| 454 } | 460 } |
| 455 FetchedCategoriesVector categories; | 461 FetchedCategoriesVector categories; |
| 456 if (!JsonToSnippets(*result, &categories)) { | 462 |
| 463 if (!JsonToSnippets(*result, &categories, fetch_time)) { | |
| 457 LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_; | 464 LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_; |
| 458 FetchFinished(OptionalFetchedCategories(), std::move(callback), | 465 FetchFinished(OptionalFetchedCategories(), std::move(callback), |
| 459 FetchResult::INVALID_SNIPPET_CONTENT_ERROR, std::string()); | 466 FetchResult::INVALID_SNIPPET_CONTENT_ERROR, std::string()); |
| 460 return; | 467 return; |
| 461 } | 468 } |
| 462 // Filter out unwanted categories if necessary. | 469 // Filter out unwanted categories if necessary. |
| 463 // TODO(fhorschig): As soon as the server supports filtering by category, | 470 // TODO(fhorschig): As soon as the server supports filtering by category, |
| 464 // adjust the request instead of over-fetching and filtering here. | 471 // adjust the request instead of over-fetching and filtering here. |
| 465 FilterCategories(&categories, request->exclusive_category()); | 472 FilterCategories(&categories, request->exclusive_category()); |
| 466 | 473 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 482 static_cast<int>(FetchResult::RESULT_MAX)); | 489 static_cast<int>(FetchResult::RESULT_MAX)); |
| 483 | 490 |
| 484 DVLOG(1) << "Fetch finished: " << last_status_; | 491 DVLOG(1) << "Fetch finished: " << last_status_; |
| 485 | 492 |
| 486 std::move(callback).Run(FetchResultToStatus(fetch_result), | 493 std::move(callback).Run(FetchResultToStatus(fetch_result), |
| 487 std::move(categories)); | 494 std::move(categories)); |
| 488 } | 495 } |
| 489 | 496 |
| 490 bool RemoteSuggestionsFetcher::JsonToSnippets( | 497 bool RemoteSuggestionsFetcher::JsonToSnippets( |
| 491 const base::Value& parsed, | 498 const base::Value& parsed, |
| 492 FetchedCategoriesVector* categories) { | 499 FetchedCategoriesVector* categories, |
| 500 const base::Time& fetch_time) { | |
| 493 const base::DictionaryValue* top_dict = nullptr; | 501 const base::DictionaryValue* top_dict = nullptr; |
| 494 if (!parsed.GetAsDictionary(&top_dict)) { | 502 if (!parsed.GetAsDictionary(&top_dict)) { |
| 495 return false; | 503 return false; |
| 496 } | 504 } |
| 497 | 505 |
| 498 switch (fetch_api_) { | 506 switch (fetch_api_) { |
| 499 case FetchAPI::CHROME_READER_API: { | 507 case FetchAPI::CHROME_READER_API: { |
| 500 const int kUnusedRemoteCategoryId = -1; | 508 const int kUnusedRemoteCategoryId = -1; |
| 501 categories->push_back(FetchedCategory( | 509 categories->push_back(FetchedCategory( |
| 502 Category::FromKnownCategory(KnownCategories::ARTICLES), | 510 Category::FromKnownCategory(KnownCategories::ARTICLES), |
| 503 BuildArticleCategoryInfo(base::nullopt))); | 511 BuildArticleCategoryInfo(base::nullopt))); |
| 504 | 512 |
| 505 const base::ListValue* recos = nullptr; | 513 const base::ListValue* recos = nullptr; |
| 506 return top_dict->GetList("recos", &recos) && | 514 return top_dict->GetList("recos", &recos) && |
| 507 AddSuggestionsFromListValue(/*content_suggestions_api=*/false, | 515 AddSuggestionsFromListValue( |
| 508 kUnusedRemoteCategoryId, *recos, | 516 /*content_suggestions_api=*/false, kUnusedRemoteCategoryId, |
| 509 &categories->back().suggestions); | 517 *recos, &categories->back().suggestions, fetch_time); |
| 510 } | 518 } |
| 511 | 519 |
| 512 case FetchAPI::CHROME_CONTENT_SUGGESTIONS_API: { | 520 case FetchAPI::CHROME_CONTENT_SUGGESTIONS_API: { |
| 513 const base::ListValue* categories_value = nullptr; | 521 const base::ListValue* categories_value = nullptr; |
| 514 if (!top_dict->GetList("categories", &categories_value)) { | 522 if (!top_dict->GetList("categories", &categories_value)) { |
| 515 return false; | 523 return false; |
| 516 } | 524 } |
| 517 | 525 |
| 518 for (const auto& v : *categories_value) { | 526 for (const auto& v : *categories_value) { |
| 519 std::string utf8_title; | 527 std::string utf8_title; |
| 520 int remote_category_id = -1; | 528 int remote_category_id = -1; |
| 521 const base::DictionaryValue* category_value = nullptr; | 529 const base::DictionaryValue* category_value = nullptr; |
| 522 if (!(v->GetAsDictionary(&category_value) && | 530 if (!(v->GetAsDictionary(&category_value) && |
| 523 category_value->GetString("localizedTitle", &utf8_title) && | 531 category_value->GetString("localizedTitle", &utf8_title) && |
| 524 category_value->GetInteger("id", &remote_category_id) && | 532 category_value->GetInteger("id", &remote_category_id) && |
| 525 (remote_category_id > 0))) { | 533 (remote_category_id > 0))) { |
| 526 return false; | 534 return false; |
| 527 } | 535 } |
| 528 | 536 |
| 529 RemoteSuggestion::PtrVector suggestions; | 537 RemoteSuggestion::PtrVector suggestions; |
| 530 const base::ListValue* suggestions_list = nullptr; | 538 const base::ListValue* suggestions_list = nullptr; |
| 531 // Absence of a list of suggestions is treated as an empty list, which | 539 // Absence of a list of suggestions is treated as an empty list, which |
| 532 // is permissible. | 540 // is permissible. |
| 533 if (category_value->GetList("suggestions", &suggestions_list)) { | 541 if (category_value->GetList("suggestions", &suggestions_list)) { |
| 534 if (!AddSuggestionsFromListValue( | 542 if (!AddSuggestionsFromListValue( |
| 535 /*content_suggestions_api=*/true, remote_category_id, | 543 /*content_suggestions_api=*/true, remote_category_id, |
| 536 *suggestions_list, &suggestions)) { | 544 *suggestions_list, &suggestions, fetch_time)) { |
| 537 return false; | 545 return false; |
| 538 } | 546 } |
| 539 } | 547 } |
| 540 Category category = Category::FromRemoteCategory(remote_category_id); | 548 Category category = Category::FromRemoteCategory(remote_category_id); |
| 541 if (category.IsKnownCategory(KnownCategories::ARTICLES)) { | 549 if (category.IsKnownCategory(KnownCategories::ARTICLES)) { |
| 542 categories->push_back(FetchedCategory( | 550 categories->push_back(FetchedCategory( |
| 543 category, | 551 category, |
| 544 BuildArticleCategoryInfo(base::UTF8ToUTF16(utf8_title)))); | 552 BuildArticleCategoryInfo(base::UTF8ToUTF16(utf8_title)))); |
| 545 } else { | 553 } else { |
| 546 // TODO(tschumann): Right now, the backend does not yet populate this | 554 // TODO(tschumann): Right now, the backend does not yet populate this |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 571 interactive_request); | 579 interactive_request); |
| 572 case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER: | 580 case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER: |
| 573 return request_throttler_active_suggestions_consumer_ | 581 return request_throttler_active_suggestions_consumer_ |
| 574 .DemandQuotaForRequest(interactive_request); | 582 .DemandQuotaForRequest(interactive_request); |
| 575 } | 583 } |
| 576 NOTREACHED(); | 584 NOTREACHED(); |
| 577 return false; | 585 return false; |
| 578 } | 586 } |
| 579 | 587 |
| 580 } // namespace ntp_snippets | 588 } // namespace ntp_snippets |
| OLD | NEW |