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" |
7 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "components/sync/protocol/reading_list_specifics.pb.h" |
8 #include "ios/chrome/browser/reading_list/offline_url_utils.h" | 10 #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" |
9 | 13 |
10 // The backoff time is the following: 10min, 10min, 1h, 2h, 2h..., starting | 14 // The backoff time is the following: 10min, 10min, 1h, 2h, 2h..., starting |
11 // after the first failure. | 15 // after the first failure. |
12 const net::BackoffEntry::Policy ReadingListEntry::kBackoffPolicy = { | 16 const net::BackoffEntry::Policy ReadingListEntry::kBackoffPolicy = { |
13 // Number of initial errors (in sequence) to ignore before applying | 17 // Number of initial errors (in sequence) to ignore before applying |
14 // exponential back-off rules. | 18 // exponential back-off rules. |
15 2, | 19 2, |
16 | 20 |
17 // Initial delay for exponential back-off in ms. | 21 // Initial delay for exponential back-off in ms. |
18 10 * 60 * 1000, // 10 minutes. | 22 10 * 60 * 1000, // 10 minutes. |
(...skipping 14 matching lines...) Expand all Loading... |
33 | 37 |
34 true, // Don't use initial delay unless the last request was an error. | 38 true, // Don't use initial delay unless the last request was an error. |
35 }; | 39 }; |
36 | 40 |
37 ReadingListEntry::ReadingListEntry(const GURL& url, const std::string& title) | 41 ReadingListEntry::ReadingListEntry(const GURL& url, const std::string& title) |
38 : ReadingListEntry(url, title, nullptr){}; | 42 : ReadingListEntry(url, title, nullptr){}; |
39 | 43 |
40 ReadingListEntry::ReadingListEntry(const GURL& url, | 44 ReadingListEntry::ReadingListEntry(const GURL& url, |
41 const std::string& title, | 45 const std::string& title, |
42 std::unique_ptr<net::BackoffEntry> backoff) | 46 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) |
43 : url_(url), | 65 : url_(url), |
44 title_(title), | 66 title_(title), |
45 distilled_state_(WAITING), | 67 distilled_path_(distilled_path), |
46 failed_download_counter_(0) { | 68 distilled_state_(distilled_state), |
| 69 failed_download_counter_(failed_download_counter), |
| 70 creation_time_us_(creation_time), |
| 71 update_time_us_(update_time) { |
47 if (backoff) { | 72 if (backoff) { |
48 backoff_ = std::move(backoff); | 73 backoff_ = std::move(backoff); |
49 } else { | 74 } else { |
50 backoff_ = base::MakeUnique<net::BackoffEntry>(&kBackoffPolicy); | 75 backoff_ = base::MakeUnique<net::BackoffEntry>(&kBackoffPolicy); |
51 } | 76 } |
| 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 } |
52 DCHECK(!url.is_empty()); | 83 DCHECK(!url.is_empty()); |
53 DCHECK(url.is_valid()); | 84 DCHECK(url.is_valid()); |
54 } | 85 } |
55 | 86 |
56 ReadingListEntry::ReadingListEntry(ReadingListEntry&& entry) | 87 ReadingListEntry::ReadingListEntry(ReadingListEntry&& entry) |
57 : url_(std::move(entry.url_)), | 88 : url_(std::move(entry.url_)), |
58 title_(std::move(entry.title_)), | 89 title_(std::move(entry.title_)), |
59 distilled_path_(std::move(entry.distilled_path_)), | 90 distilled_path_(std::move(entry.distilled_path_)), |
60 distilled_state_(std::move(entry.distilled_state_)), | 91 distilled_state_(std::move(entry.distilled_state_)), |
61 backoff_(std::move(entry.backoff_)), | 92 backoff_(std::move(entry.backoff_)), |
62 failed_download_counter_(std::move(entry.failed_download_counter_)) {} | 93 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_)) {} |
63 | 96 |
64 ReadingListEntry::~ReadingListEntry() {} | 97 ReadingListEntry::~ReadingListEntry() {} |
65 | 98 |
66 const GURL& ReadingListEntry::URL() const { | 99 const GURL& ReadingListEntry::URL() const { |
67 return url_; | 100 return url_; |
68 } | 101 } |
69 | 102 |
70 const std::string& ReadingListEntry::Title() const { | 103 const std::string& ReadingListEntry::Title() const { |
71 return title_; | 104 return title_; |
72 } | 105 } |
(...skipping 18 matching lines...) Expand all Loading... |
91 return failed_download_counter_; | 124 return failed_download_counter_; |
92 } | 125 } |
93 | 126 |
94 ReadingListEntry& ReadingListEntry::operator=(ReadingListEntry&& other) { | 127 ReadingListEntry& ReadingListEntry::operator=(ReadingListEntry&& other) { |
95 url_ = std::move(other.url_); | 128 url_ = std::move(other.url_); |
96 title_ = std::move(other.title_); | 129 title_ = std::move(other.title_); |
97 distilled_path_ = std::move(other.distilled_path_); | 130 distilled_path_ = std::move(other.distilled_path_); |
98 distilled_state_ = std::move(other.distilled_state_); | 131 distilled_state_ = std::move(other.distilled_state_); |
99 backoff_ = std::move(other.backoff_); | 132 backoff_ = std::move(other.backoff_); |
100 failed_download_counter_ = std::move(other.failed_download_counter_); | 133 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_); |
101 return *this; | 136 return *this; |
102 } | 137 } |
103 | 138 |
104 bool ReadingListEntry::operator==(const ReadingListEntry& other) const { | 139 bool ReadingListEntry::operator==(const ReadingListEntry& other) const { |
105 return url_ == other.url_; | 140 return url_ == other.url_; |
106 } | 141 } |
107 | 142 |
108 void ReadingListEntry::SetTitle(const std::string& title) { | 143 void ReadingListEntry::SetTitle(const std::string& title) { |
109 title_ = title; | 144 title_ = title; |
110 } | 145 } |
(...skipping 13 matching lines...) Expand all Loading... |
124 // non-error state to an error state. | 159 // non-error state to an error state. |
125 if ((distilled_state == WILL_RETRY || distilled_state == ERROR) && | 160 if ((distilled_state == WILL_RETRY || distilled_state == ERROR) && |
126 distilled_state_ != WILL_RETRY && distilled_state_ != ERROR) { | 161 distilled_state_ != WILL_RETRY && distilled_state_ != ERROR) { |
127 backoff_->InformOfRequest(false); | 162 backoff_->InformOfRequest(false); |
128 failed_download_counter_++; | 163 failed_download_counter_++; |
129 } | 164 } |
130 | 165 |
131 distilled_state_ = distilled_state; | 166 distilled_state_ = distilled_state; |
132 distilled_path_ = base::FilePath(); | 167 distilled_path_ = base::FilePath(); |
133 } | 168 } |
| 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 |