Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/ntp_snippets_service.h" | 5 #include "components/ntp_snippets/ntp_snippets_service.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iterator> | 8 #include <iterator> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 13 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
| 14 #include "base/json/json_reader.h" | 14 #include "base/json/json_reader.h" |
| 15 #include "base/location.h" | 15 #include "base/location.h" |
| 16 #include "base/metrics/sparse_histogram.h" | |
| 16 #include "base/path_service.h" | 17 #include "base/path_service.h" |
| 17 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
| 19 #include "base/task_runner_util.h" | 20 #include "base/task_runner_util.h" |
| 20 #include "base/time/time.h" | 21 #include "base/time/time.h" |
| 21 #include "base/values.h" | 22 #include "base/values.h" |
| 22 #include "components/ntp_snippets/pref_names.h" | 23 #include "components/ntp_snippets/pref_names.h" |
| 23 #include "components/ntp_snippets/switches.h" | 24 #include "components/ntp_snippets/switches.h" |
| 24 #include "components/prefs/pref_registry_simple.h" | 25 #include "components/prefs/pref_registry_simple.h" |
| 25 #include "components/prefs/pref_service.h" | 26 #include "components/prefs/pref_service.h" |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 121 const ChromeSuggestion& suggestion = suggestions.suggestions(i); | 122 const ChromeSuggestion& suggestion = suggestions.suggestions(i); |
| 122 GURL url(suggestion.url()); | 123 GURL url(suggestion.url()); |
| 123 if (url.is_valid()) | 124 if (url.is_valid()) |
| 124 hosts.insert(url.host()); | 125 hosts.insert(url.host()); |
| 125 } | 126 } |
| 126 return hosts; | 127 return hosts; |
| 127 } | 128 } |
| 128 | 129 |
| 129 const char kContentInfo[] = "contentInfo"; | 130 const char kContentInfo[] = "contentInfo"; |
| 130 | 131 |
| 131 // Parses snippets from |list| and adds them to |snippets|. Returns true on | 132 // Parses snippets from |list| and adds them to |snippets|. |downloaded| should |
| 132 // success, false if anything went wrong. | 133 // be true if we are adding snippets that have been freshly downloaded, and |
| 134 // false if we are loading from prefs. Returns true on success, false if | |
| 135 // anything went wrong. | |
| 133 bool AddSnippetsFromListValue(const base::ListValue& list, | 136 bool AddSnippetsFromListValue(const base::ListValue& list, |
| 134 NTPSnippetsService::NTPSnippetStorage* snippets) { | 137 NTPSnippetsService::NTPSnippetStorage* snippets, |
| 138 bool downloaded) { | |
| 139 int num_incomplete_snippets = 0; | |
| 135 for (const base::Value* const value : list) { | 140 for (const base::Value* const value : list) { |
| 136 const base::DictionaryValue* dict = nullptr; | 141 const base::DictionaryValue* dict = nullptr; |
| 137 if (!value->GetAsDictionary(&dict)) | 142 if (!value->GetAsDictionary(&dict)) |
| 138 return false; | 143 return false; |
| 139 | 144 |
| 140 const base::DictionaryValue* content = nullptr; | 145 const base::DictionaryValue* content = nullptr; |
| 141 if (!dict->GetDictionary(kContentInfo, &content)) | 146 if (!dict->GetDictionary(kContentInfo, &content)) |
| 142 return false; | 147 return false; |
| 143 std::unique_ptr<NTPSnippet> snippet = | 148 std::unique_ptr<NTPSnippet> snippet = |
| 144 NTPSnippet::CreateFromDictionary(*content); | 149 NTPSnippet::CreateFromDictionary(*content); |
| 145 if (!snippet) | 150 if (!snippet) |
| 146 return false; | 151 return false; |
| 147 | 152 |
| 148 snippets->push_back(std::move(snippet)); | 153 // Fill in default publish/expiry dates where required. |
|
Marc Treib
2016/04/29 12:11:20
This will now also run when we're loading snippets
May
2016/04/29 12:19:09
We should never store snippets without a publish/e
Marc Treib
2016/04/29 12:33:32
Yes, please. It "should" be a no-op in those cases
May
2016/04/29 17:00:15
Sure, moved the snippet discarding logic into Load
| |
| 154 if (snippet->publish_date().is_null()) | |
| 155 snippet->set_publish_date(base::Time::Now()); | |
| 156 if (snippet->expiry_date().is_null()) { | |
| 157 snippet->set_expiry_date( | |
| 158 snippet->publish_date() + | |
| 159 base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins)); | |
| 160 } | |
| 161 | |
| 162 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 163 switches::kAddIncompleteSnippets)) { | |
| 164 snippets->push_back(std::move(snippet)); | |
| 165 } else if (snippet->is_complete()) { | |
| 166 snippets->push_back(std::move(snippet)); | |
| 167 } else { | |
| 168 ++num_incomplete_snippets; | |
| 169 } | |
| 149 } | 170 } |
| 171 | |
| 172 if (num_incomplete_snippets > 0) | |
| 173 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.IncompleteSnippets", | |
| 174 num_incomplete_snippets); | |
| 175 | |
| 150 return true; | 176 return true; |
| 151 } | 177 } |
| 152 | 178 |
| 153 std::unique_ptr<base::ListValue> SnippetsToListValue( | 179 std::unique_ptr<base::ListValue> SnippetsToListValue( |
| 154 const NTPSnippetsService::NTPSnippetStorage& snippets) { | 180 const NTPSnippetsService::NTPSnippetStorage& snippets) { |
| 155 std::unique_ptr<base::ListValue> list(new base::ListValue); | 181 std::unique_ptr<base::ListValue> list(new base::ListValue); |
| 156 for (const auto& snippet : snippets) { | 182 for (const auto& snippet : snippets) { |
| 157 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue); | 183 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue); |
| 158 dict->Set(kContentInfo, snippet->ToDictionary()); | 184 dict->Set(kContentInfo, snippet->ToDictionary()); |
| 159 list->Append(std::move(dict)); | 185 list->Append(std::move(dict)); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 277 // |suggestions_service_| can be null in tests. | 303 // |suggestions_service_| can be null in tests. |
| 278 if (!suggestions_service_) | 304 if (!suggestions_service_) |
| 279 return std::set<std::string>(); | 305 return std::set<std::string>(); |
| 280 | 306 |
| 281 // TODO(treib) this should just call GetSnippetHostsFromPrefs | 307 // TODO(treib) this should just call GetSnippetHostsFromPrefs |
| 282 return GetSuggestionsHostsImpl( | 308 return GetSuggestionsHostsImpl( |
| 283 suggestions_service_->GetSuggestionsDataFromCache()); | 309 suggestions_service_->GetSuggestionsDataFromCache()); |
| 284 } | 310 } |
| 285 | 311 |
| 286 bool NTPSnippetsService::DiscardSnippet(const GURL& url) { | 312 bool NTPSnippetsService::DiscardSnippet(const GURL& url) { |
| 287 auto it = std::find_if(snippets_.begin(), snippets_.end(), | 313 auto it = |
| 288 [&url](const std::unique_ptr<NTPSnippet>& snippet) { | 314 std::find_if(snippets_.begin(), snippets_.end(), |
| 289 return snippet->url() == url; | 315 [&url](const std::unique_ptr<NTPSnippet>& snippet) { |
| 290 }); | 316 return snippet->url() == url || snippet->best_source().url; |
|
Marc Treib
2016/04/29 12:11:20
This will just check if |snippet->best_source().ur
May
2016/04/29 12:19:09
Ack -- fixed. And apparently it can be turned into
| |
| 317 }); | |
| 291 if (it == snippets_.end()) | 318 if (it == snippets_.end()) |
| 292 return false; | 319 return false; |
| 293 discarded_snippets_.push_back(std::move(*it)); | 320 discarded_snippets_.push_back(std::move(*it)); |
| 294 snippets_.erase(it); | 321 snippets_.erase(it); |
| 295 StoreDiscardedSnippetsToPrefs(); | 322 StoreDiscardedSnippetsToPrefs(); |
| 296 StoreSnippetsToPrefs(); | 323 StoreSnippetsToPrefs(); |
| 297 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, | 324 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, |
| 298 NTPSnippetsServiceLoaded()); | 325 NTPSnippetsServiceLoaded()); |
| 299 return true; | 326 return true; |
| 300 } | 327 } |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 | 414 |
| 388 const base::ListValue* list = nullptr; | 415 const base::ListValue* list = nullptr; |
| 389 if (!top_dict->GetList("recos", &list)) | 416 if (!top_dict->GetList("recos", &list)) |
| 390 return false; | 417 return false; |
| 391 | 418 |
| 392 return LoadFromListValue(*list); | 419 return LoadFromListValue(*list); |
| 393 } | 420 } |
| 394 | 421 |
| 395 bool NTPSnippetsService::LoadFromListValue(const base::ListValue& list) { | 422 bool NTPSnippetsService::LoadFromListValue(const base::ListValue& list) { |
| 396 NTPSnippetStorage new_snippets; | 423 NTPSnippetStorage new_snippets; |
| 397 if (!AddSnippetsFromListValue(list, &new_snippets)) | 424 if (!AddSnippetsFromListValue(list, &new_snippets, true)) |
| 398 return false; | 425 return false; |
| 399 | 426 |
| 400 // Remove new snippets that we already have, or that have been discarded. | 427 // Remove new snippets that we already have, or that have been discarded. |
| 401 new_snippets.erase( | 428 new_snippets.erase( |
| 402 std::remove_if(new_snippets.begin(), new_snippets.end(), | 429 std::remove_if(new_snippets.begin(), new_snippets.end(), |
| 403 [this](const std::unique_ptr<NTPSnippet>& snippet) { | 430 [this](const std::unique_ptr<NTPSnippet>& snippet) { |
| 404 return ContainsSnippet(discarded_snippets_, snippet) || | 431 return ContainsSnippet(discarded_snippets_, snippet) || |
| 405 ContainsSnippet(snippets_, snippet); | 432 ContainsSnippet(snippets_, snippet); |
| 406 }), | 433 }), |
| 407 new_snippets.end()); | 434 new_snippets.end()); |
| 408 | 435 |
| 409 // Fill in default publish/expiry dates where required. | |
| 410 for (std::unique_ptr<NTPSnippet>& snippet : new_snippets) { | |
| 411 if (snippet->publish_date().is_null()) | |
| 412 snippet->set_publish_date(base::Time::Now()); | |
| 413 if (snippet->expiry_date().is_null()) { | |
| 414 snippet->set_expiry_date( | |
| 415 snippet->publish_date() + | |
| 416 base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins)); | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 // Insert the new snippets at the front. | 436 // Insert the new snippets at the front. |
| 421 snippets_.insert(snippets_.begin(), | 437 snippets_.insert(snippets_.begin(), |
| 422 std::make_move_iterator(new_snippets.begin()), | 438 std::make_move_iterator(new_snippets.begin()), |
| 423 std::make_move_iterator(new_snippets.end())); | 439 std::make_move_iterator(new_snippets.end())); |
| 424 | 440 |
| 425 // If there are more snippets now than we want to show, drop the extra ones | 441 // If there are more snippets now than we want to show, drop the extra ones |
| 426 // from the end of the list. | 442 // from the end of the list. |
| 427 if (snippets_.size() > kMaxSnippetCount) | 443 if (snippets_.size() > kMaxSnippetCount) |
| 428 snippets_.resize(kMaxSnippetCount); | 444 snippets_.resize(kMaxSnippetCount); |
| 429 | 445 |
| 430 return true; | 446 return true; |
| 431 } | 447 } |
| 432 | 448 |
| 433 void NTPSnippetsService::LoadSnippetsFromPrefs() { | 449 void NTPSnippetsService::LoadSnippetsFromPrefs() { |
| 434 bool success = LoadFromListValue(*pref_service_->GetList(prefs::kSnippets)); | 450 bool success = LoadFromListValue(*pref_service_->GetList(prefs::kSnippets)); |
| 435 DCHECK(success) << "Failed to parse snippets from prefs"; | 451 DCHECK(success) << "Failed to parse snippets from prefs"; |
| 436 | 452 |
| 437 LoadingSnippetsFinished(); | 453 LoadingSnippetsFinished(); |
| 438 } | 454 } |
| 439 | 455 |
| 440 void NTPSnippetsService::StoreSnippetsToPrefs() { | 456 void NTPSnippetsService::StoreSnippetsToPrefs() { |
| 441 pref_service_->Set(prefs::kSnippets, *SnippetsToListValue(snippets_)); | 457 pref_service_->Set(prefs::kSnippets, *SnippetsToListValue(snippets_)); |
| 442 } | 458 } |
| 443 | 459 |
| 444 void NTPSnippetsService::LoadDiscardedSnippetsFromPrefs() { | 460 void NTPSnippetsService::LoadDiscardedSnippetsFromPrefs() { |
| 445 discarded_snippets_.clear(); | 461 discarded_snippets_.clear(); |
| 446 bool success = AddSnippetsFromListValue( | 462 bool success = AddSnippetsFromListValue( |
| 447 *pref_service_->GetList(prefs::kDiscardedSnippets), | 463 *pref_service_->GetList(prefs::kDiscardedSnippets), &discarded_snippets_, |
| 448 &discarded_snippets_); | 464 false); |
| 449 DCHECK(success) << "Failed to parse discarded snippets from prefs"; | 465 DCHECK(success) << "Failed to parse discarded snippets from prefs"; |
| 450 } | 466 } |
| 451 | 467 |
| 452 void NTPSnippetsService::StoreDiscardedSnippetsToPrefs() { | 468 void NTPSnippetsService::StoreDiscardedSnippetsToPrefs() { |
| 453 pref_service_->Set(prefs::kDiscardedSnippets, | 469 pref_service_->Set(prefs::kDiscardedSnippets, |
| 454 *SnippetsToListValue(discarded_snippets_)); | 470 *SnippetsToListValue(discarded_snippets_)); |
| 455 } | 471 } |
| 456 | 472 |
| 457 std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const { | 473 std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const { |
| 458 std::set<std::string> hosts; | 474 std::set<std::string> hosts; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 if (snippet->expiry_date() < next_expiry) | 526 if (snippet->expiry_date() < next_expiry) |
| 511 next_expiry = snippet->expiry_date(); | 527 next_expiry = snippet->expiry_date(); |
| 512 } | 528 } |
| 513 DCHECK_GT(next_expiry, expiry); | 529 DCHECK_GT(next_expiry, expiry); |
| 514 expiry_timer_.Start(FROM_HERE, next_expiry - expiry, | 530 expiry_timer_.Start(FROM_HERE, next_expiry - expiry, |
| 515 base::Bind(&NTPSnippetsService::LoadingSnippetsFinished, | 531 base::Bind(&NTPSnippetsService::LoadingSnippetsFinished, |
| 516 base::Unretained(this))); | 532 base::Unretained(this))); |
| 517 } | 533 } |
| 518 | 534 |
| 519 } // namespace ntp_snippets | 535 } // namespace ntp_snippets |
| OLD | NEW |