| 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 "ios/chrome/browser/reading_list/reading_list_entry.h" | 5 #include "ios/chrome/browser/reading_list/reading_list_entry.h" |
| 6 | 6 |
| 7 #include "base/json/json_string_value_serializer.h" | |
| 8 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
| 9 #include "components/sync/protocol/reading_list_specifics.pb.h" | |
| 10 #include "ios/chrome/browser/reading_list/offline_url_utils.h" | 8 #include "ios/chrome/browser/reading_list/offline_url_utils.h" |
| 11 #include "ios/chrome/browser/reading_list/proto/reading_list.pb.h" | |
| 12 #include "net/base/backoff_entry_serializer.h" | |
| 13 | 9 |
| 14 // The backoff time is the following: 10min, 10min, 1h, 2h, 2h..., starting | 10 // The backoff time is the following: 10min, 10min, 1h, 2h, 2h..., starting |
| 15 // after the first failure. | 11 // after the first failure. |
| 16 const net::BackoffEntry::Policy ReadingListEntry::kBackoffPolicy = { | 12 const net::BackoffEntry::Policy ReadingListEntry::kBackoffPolicy = { |
| 17 // Number of initial errors (in sequence) to ignore before applying | 13 // Number of initial errors (in sequence) to ignore before applying |
| 18 // exponential back-off rules. | 14 // exponential back-off rules. |
| 19 2, | 15 2, |
| 20 | 16 |
| 21 // Initial delay for exponential back-off in ms. | 17 // Initial delay for exponential back-off in ms. |
| 22 10 * 60 * 1000, // 10 minutes. | 18 10 * 60 * 1000, // 10 minutes. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 37 | 33 |
| 38 true, // Don't use initial delay unless the last request was an error. | 34 true, // Don't use initial delay unless the last request was an error. |
| 39 }; | 35 }; |
| 40 | 36 |
| 41 ReadingListEntry::ReadingListEntry(const GURL& url, const std::string& title) | 37 ReadingListEntry::ReadingListEntry(const GURL& url, const std::string& title) |
| 42 : ReadingListEntry(url, title, nullptr){}; | 38 : ReadingListEntry(url, title, nullptr){}; |
| 43 | 39 |
| 44 ReadingListEntry::ReadingListEntry(const GURL& url, | 40 ReadingListEntry::ReadingListEntry(const GURL& url, |
| 45 const std::string& title, | 41 const std::string& title, |
| 46 std::unique_ptr<net::BackoffEntry> backoff) | 42 std::unique_ptr<net::BackoffEntry> backoff) |
| 47 : ReadingListEntry(url, | |
| 48 title, | |
| 49 0, | |
| 50 0, | |
| 51 WAITING, | |
| 52 base::FilePath(), | |
| 53 0, | |
| 54 std::move(backoff)) {} | |
| 55 | |
| 56 ReadingListEntry::ReadingListEntry( | |
| 57 const GURL& url, | |
| 58 const std::string& title, | |
| 59 int64_t creation_time, | |
| 60 int64_t update_time, | |
| 61 ReadingListEntry::DistillationState distilled_state, | |
| 62 const base::FilePath& distilled_path, | |
| 63 int failed_download_counter, | |
| 64 std::unique_ptr<net::BackoffEntry> backoff) | |
| 65 : url_(url), | 43 : url_(url), |
| 66 title_(title), | 44 title_(title), |
| 67 distilled_path_(distilled_path), | 45 distilled_state_(WAITING), |
| 68 distilled_state_(distilled_state), | 46 failed_download_counter_(0) { |
| 69 failed_download_counter_(failed_download_counter), | |
| 70 creation_time_us_(creation_time), | |
| 71 update_time_us_(update_time) { | |
| 72 if (backoff) { | 47 if (backoff) { |
| 73 backoff_ = std::move(backoff); | 48 backoff_ = std::move(backoff); |
| 74 } else { | 49 } else { |
| 75 backoff_ = base::MakeUnique<net::BackoffEntry>(&kBackoffPolicy); | 50 backoff_ = base::MakeUnique<net::BackoffEntry>(&kBackoffPolicy); |
| 76 } | 51 } |
| 77 if (creation_time_us_ == 0) { | |
| 78 DCHECK(update_time_us_ == 0); | |
| 79 creation_time_us_ = | |
| 80 (base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds(); | |
| 81 update_time_us_ = creation_time_us_; | |
| 82 } | |
| 83 DCHECK(!url.is_empty()); | 52 DCHECK(!url.is_empty()); |
| 84 DCHECK(url.is_valid()); | 53 DCHECK(url.is_valid()); |
| 85 } | 54 } |
| 86 | 55 |
| 87 ReadingListEntry::ReadingListEntry(ReadingListEntry&& entry) | 56 ReadingListEntry::ReadingListEntry(ReadingListEntry&& entry) |
| 88 : url_(std::move(entry.url_)), | 57 : url_(std::move(entry.url_)), |
| 89 title_(std::move(entry.title_)), | 58 title_(std::move(entry.title_)), |
| 90 distilled_path_(std::move(entry.distilled_path_)), | 59 distilled_path_(std::move(entry.distilled_path_)), |
| 91 distilled_state_(std::move(entry.distilled_state_)), | 60 distilled_state_(std::move(entry.distilled_state_)), |
| 92 backoff_(std::move(entry.backoff_)), | 61 backoff_(std::move(entry.backoff_)), |
| 93 failed_download_counter_(std::move(entry.failed_download_counter_)), | 62 failed_download_counter_(std::move(entry.failed_download_counter_)) {} |
| 94 creation_time_us_(std::move(entry.creation_time_us_)), | |
| 95 update_time_us_(std::move(entry.update_time_us_)) {} | |
| 96 | 63 |
| 97 ReadingListEntry::~ReadingListEntry() {} | 64 ReadingListEntry::~ReadingListEntry() {} |
| 98 | 65 |
| 99 const GURL& ReadingListEntry::URL() const { | 66 const GURL& ReadingListEntry::URL() const { |
| 100 return url_; | 67 return url_; |
| 101 } | 68 } |
| 102 | 69 |
| 103 const std::string& ReadingListEntry::Title() const { | 70 const std::string& ReadingListEntry::Title() const { |
| 104 return title_; | 71 return title_; |
| 105 } | 72 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 124 return failed_download_counter_; | 91 return failed_download_counter_; |
| 125 } | 92 } |
| 126 | 93 |
| 127 ReadingListEntry& ReadingListEntry::operator=(ReadingListEntry&& other) { | 94 ReadingListEntry& ReadingListEntry::operator=(ReadingListEntry&& other) { |
| 128 url_ = std::move(other.url_); | 95 url_ = std::move(other.url_); |
| 129 title_ = std::move(other.title_); | 96 title_ = std::move(other.title_); |
| 130 distilled_path_ = std::move(other.distilled_path_); | 97 distilled_path_ = std::move(other.distilled_path_); |
| 131 distilled_state_ = std::move(other.distilled_state_); | 98 distilled_state_ = std::move(other.distilled_state_); |
| 132 backoff_ = std::move(other.backoff_); | 99 backoff_ = std::move(other.backoff_); |
| 133 failed_download_counter_ = std::move(other.failed_download_counter_); | 100 failed_download_counter_ = std::move(other.failed_download_counter_); |
| 134 creation_time_us_ = std::move(other.creation_time_us_); | |
| 135 update_time_us_ = std::move(other.update_time_us_); | |
| 136 return *this; | 101 return *this; |
| 137 } | 102 } |
| 138 | 103 |
| 139 bool ReadingListEntry::operator==(const ReadingListEntry& other) const { | 104 bool ReadingListEntry::operator==(const ReadingListEntry& other) const { |
| 140 return url_ == other.url_; | 105 return url_ == other.url_; |
| 141 } | 106 } |
| 142 | 107 |
| 143 void ReadingListEntry::SetTitle(const std::string& title) { | 108 void ReadingListEntry::SetTitle(const std::string& title) { |
| 144 title_ = title; | 109 title_ = title; |
| 145 } | 110 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 159 // non-error state to an error state. | 124 // non-error state to an error state. |
| 160 if ((distilled_state == WILL_RETRY || distilled_state == ERROR) && | 125 if ((distilled_state == WILL_RETRY || distilled_state == ERROR) && |
| 161 distilled_state_ != WILL_RETRY && distilled_state_ != ERROR) { | 126 distilled_state_ != WILL_RETRY && distilled_state_ != ERROR) { |
| 162 backoff_->InformOfRequest(false); | 127 backoff_->InformOfRequest(false); |
| 163 failed_download_counter_++; | 128 failed_download_counter_++; |
| 164 } | 129 } |
| 165 | 130 |
| 166 distilled_state_ = distilled_state; | 131 distilled_state_ = distilled_state; |
| 167 distilled_path_ = base::FilePath(); | 132 distilled_path_ = base::FilePath(); |
| 168 } | 133 } |
| 169 | |
| 170 int64_t ReadingListEntry::UpdateTime() const { | |
| 171 return update_time_us_; | |
| 172 } | |
| 173 | |
| 174 int64_t ReadingListEntry::CreationTime() const { | |
| 175 return creation_time_us_; | |
| 176 } | |
| 177 | |
| 178 void ReadingListEntry::MarkEntryUpdated() { | |
| 179 update_time_us_ = | |
| 180 (base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds(); | |
| 181 } | |
| 182 | |
| 183 // static | |
| 184 std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListLocal( | |
| 185 const reading_list::ReadingListLocal& pb_entry) { | |
| 186 if (!pb_entry.has_url()) { | |
| 187 return nullptr; | |
| 188 } | |
| 189 GURL url(pb_entry.url()); | |
| 190 if (url.is_empty() || !url.is_valid()) { | |
| 191 return nullptr; | |
| 192 } | |
| 193 std::string title; | |
| 194 if (pb_entry.has_title()) { | |
| 195 title = pb_entry.title(); | |
| 196 } | |
| 197 | |
| 198 int64_t creation_time_us = 0; | |
| 199 if (pb_entry.has_creation_time_us()) { | |
| 200 creation_time_us = pb_entry.creation_time_us(); | |
| 201 } | |
| 202 | |
| 203 int64_t update_time_us = 0; | |
| 204 if (pb_entry.has_update_time_us()) { | |
| 205 update_time_us = pb_entry.update_time_us(); | |
| 206 } | |
| 207 | |
| 208 ReadingListEntry::DistillationState distillation_state = | |
| 209 ReadingListEntry::WAITING; | |
| 210 if (pb_entry.has_distillation_state()) { | |
| 211 switch (pb_entry.distillation_state()) { | |
| 212 case reading_list::ReadingListLocal::WAITING: | |
| 213 distillation_state = ReadingListEntry::WAITING; | |
| 214 break; | |
| 215 case reading_list::ReadingListLocal::PROCESSING: | |
| 216 distillation_state = ReadingListEntry::PROCESSING; | |
| 217 break; | |
| 218 case reading_list::ReadingListLocal::PROCESSED: | |
| 219 distillation_state = ReadingListEntry::PROCESSED; | |
| 220 break; | |
| 221 case reading_list::ReadingListLocal::WILL_RETRY: | |
| 222 distillation_state = ReadingListEntry::WILL_RETRY; | |
| 223 break; | |
| 224 case reading_list::ReadingListLocal::ERROR: | |
| 225 distillation_state = ReadingListEntry::ERROR; | |
| 226 break; | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 base::FilePath distilled_path; | |
| 231 if (pb_entry.has_distilled_path()) { | |
| 232 distilled_path = base::FilePath(pb_entry.distilled_path()); | |
| 233 } | |
| 234 | |
| 235 int64_t failed_download_counter = 0; | |
| 236 if (pb_entry.has_failed_download_counter()) { | |
| 237 failed_download_counter = pb_entry.failed_download_counter(); | |
| 238 } | |
| 239 | |
| 240 std::unique_ptr<net::BackoffEntry> backoff; | |
| 241 if (pb_entry.has_backoff()) { | |
| 242 JSONStringValueDeserializer deserializer(pb_entry.backoff()); | |
| 243 std::unique_ptr<base::Value> value( | |
| 244 deserializer.Deserialize(nullptr, nullptr)); | |
| 245 if (value) { | |
| 246 backoff = net::BackoffEntrySerializer::DeserializeFromValue( | |
| 247 *value, &kBackoffPolicy, nullptr, base::Time::Now()); | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 return base::WrapUnique<ReadingListEntry>(new ReadingListEntry( | |
| 252 url, title, creation_time_us, update_time_us, distillation_state, | |
| 253 distilled_path, failed_download_counter, std::move(backoff))); | |
| 254 } | |
| 255 | |
| 256 // static | |
| 257 std::unique_ptr<ReadingListEntry> ReadingListEntry::FromReadingListSpecifics( | |
| 258 const sync_pb::ReadingListSpecifics& pb_entry) { | |
| 259 if (!pb_entry.has_url()) { | |
| 260 return nullptr; | |
| 261 } | |
| 262 GURL url(pb_entry.url()); | |
| 263 if (url.is_empty() || !url.is_valid()) { | |
| 264 return nullptr; | |
| 265 } | |
| 266 std::string title; | |
| 267 if (pb_entry.has_title()) { | |
| 268 title = pb_entry.title(); | |
| 269 } | |
| 270 | |
| 271 int64_t creation_time_us = 0; | |
| 272 if (pb_entry.has_creation_time_us()) { | |
| 273 creation_time_us = pb_entry.creation_time_us(); | |
| 274 } | |
| 275 | |
| 276 int64_t update_time_us = 0; | |
| 277 if (pb_entry.has_update_time_us()) { | |
| 278 update_time_us = pb_entry.update_time_us(); | |
| 279 } | |
| 280 | |
| 281 return base::WrapUnique<ReadingListEntry>( | |
| 282 new ReadingListEntry(url, title, creation_time_us, update_time_us, | |
| 283 WAITING, base::FilePath(), 0, nullptr)); | |
| 284 } | |
| 285 | |
| 286 void ReadingListEntry::MergeLocalStateFrom(ReadingListEntry& other) { | |
| 287 distilled_path_ = std::move(other.distilled_path_); | |
| 288 distilled_state_ = std::move(other.distilled_state_); | |
| 289 backoff_ = std::move(other.backoff_); | |
| 290 failed_download_counter_ = std::move(other.failed_download_counter_); | |
| 291 } | |
| 292 | |
| 293 std::unique_ptr<reading_list::ReadingListLocal> | |
| 294 ReadingListEntry::AsReadingListLocal(bool read) const { | |
| 295 std::unique_ptr<reading_list::ReadingListLocal> pb_entry = | |
| 296 base::MakeUnique<reading_list::ReadingListLocal>(); | |
| 297 | |
| 298 // URL is used as the key for the database and sync as there is only one entry | |
| 299 // per URL. | |
| 300 pb_entry->set_entry_id(URL().spec()); | |
| 301 pb_entry->set_title(Title()); | |
| 302 pb_entry->set_url(URL().spec()); | |
| 303 pb_entry->set_creation_time_us(CreationTime()); | |
| 304 pb_entry->set_update_time_us(UpdateTime()); | |
| 305 | |
| 306 if (read) { | |
| 307 pb_entry->set_status(reading_list::ReadingListLocal::READ); | |
| 308 } else { | |
| 309 pb_entry->set_status(reading_list::ReadingListLocal::UNREAD); | |
| 310 } | |
| 311 | |
| 312 reading_list::ReadingListLocal::DistillationState distilation_state; | |
| 313 switch (DistilledState()) { | |
| 314 case ReadingListEntry::WAITING: | |
| 315 distilation_state = reading_list::ReadingListLocal::WAITING; | |
| 316 break; | |
| 317 case ReadingListEntry::PROCESSING: | |
| 318 distilation_state = reading_list::ReadingListLocal::PROCESSING; | |
| 319 break; | |
| 320 case ReadingListEntry::PROCESSED: | |
| 321 distilation_state = reading_list::ReadingListLocal::PROCESSED; | |
| 322 break; | |
| 323 case ReadingListEntry::WILL_RETRY: | |
| 324 distilation_state = reading_list::ReadingListLocal::WILL_RETRY; | |
| 325 break; | |
| 326 case ReadingListEntry::ERROR: | |
| 327 distilation_state = reading_list::ReadingListLocal::ERROR; | |
| 328 break; | |
| 329 } | |
| 330 pb_entry->set_distillation_state(distilation_state); | |
| 331 if (!DistilledPath().empty()) { | |
| 332 pb_entry->set_distilled_path(DistilledPath().value()); | |
| 333 } | |
| 334 pb_entry->set_failed_download_counter(failed_download_counter_); | |
| 335 | |
| 336 if (backoff_) { | |
| 337 std::unique_ptr<base::Value> backoff = | |
| 338 net::BackoffEntrySerializer::SerializeToValue(*backoff_, | |
| 339 base::Time::Now()); | |
| 340 | |
| 341 std::string output; | |
| 342 JSONStringValueSerializer serializer(&output); | |
| 343 serializer.Serialize(*backoff); | |
| 344 pb_entry->set_backoff(output); | |
| 345 } | |
| 346 return pb_entry; | |
| 347 } | |
| 348 | |
| 349 std::unique_ptr<sync_pb::ReadingListSpecifics> | |
| 350 ReadingListEntry::AsReadingListSpecifics(bool read) const { | |
| 351 std::unique_ptr<sync_pb::ReadingListSpecifics> pb_entry = | |
| 352 base::MakeUnique<sync_pb::ReadingListSpecifics>(); | |
| 353 | |
| 354 // URL is used as the key for the database and sync as there is only one entry | |
| 355 // per URL. | |
| 356 pb_entry->set_entry_id(URL().spec()); | |
| 357 pb_entry->set_title(Title()); | |
| 358 pb_entry->set_url(URL().spec()); | |
| 359 pb_entry->set_creation_time_us(CreationTime()); | |
| 360 pb_entry->set_update_time_us(UpdateTime()); | |
| 361 | |
| 362 if (read) { | |
| 363 pb_entry->set_status(sync_pb::ReadingListSpecifics::READ); | |
| 364 } else { | |
| 365 pb_entry->set_status(sync_pb::ReadingListSpecifics::UNREAD); | |
| 366 } | |
| 367 | |
| 368 return pb_entry; | |
| 369 } | |
| 370 | |
| 371 bool ReadingListEntry::CompareEntryUpdateTime(const ReadingListEntry& lhs, | |
| 372 const ReadingListEntry& rhs) { | |
| 373 return lhs.UpdateTime() > rhs.UpdateTime(); | |
| 374 } | |
| OLD | NEW |