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
3 // found in the LICENSE file.
5 #include "components/offline_pages/offline_page_model.h"
10 #include "base/files/file_util.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/sequenced_task_runner.h"
14 #include "components/offline_pages/offline_page_item.h"
15 #include "components/offline_pages/offline_page_metadata_store.h"
18 using ArchiverResult
= offline_pages::OfflinePageArchiver::ArchiverResult
;
19 using SavePageResult
= offline_pages::OfflinePageModel::SavePageResult
;
21 namespace offline_pages
{
25 SavePageResult
ToSavePageResult(ArchiverResult archiver_result
) {
26 SavePageResult result
;
27 switch (archiver_result
) {
28 case ArchiverResult::SUCCESSFULLY_CREATED
:
29 result
= SavePageResult::SUCCESS
;
31 case ArchiverResult::ERROR_DEVICE_FULL
:
32 result
= SavePageResult::DEVICE_FULL
;
34 case ArchiverResult::ERROR_CONTENT_UNAVAILABLE
:
35 result
= SavePageResult::CONTENT_UNAVAILABLE
;
37 case ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED
:
38 result
= SavePageResult::ARCHIVE_CREATION_FAILED
;
40 case ArchiverResult::ERROR_CANCELED
:
41 result
= SavePageResult::CANCELLED
;
45 result
= SavePageResult::CONTENT_UNAVAILABLE
;
50 void DeleteArchiveFile(const base::FilePath
& file_path
, bool* success
) {
52 *success
= base::DeleteFile(file_path
, false);
57 OfflinePageModel::OfflinePageModel(
58 scoped_ptr
<OfflinePageMetadataStore
> store
,
59 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
)
60 : store_(store
.Pass()),
62 task_runner_(task_runner
),
63 weak_ptr_factory_(this) {
64 store_
->Load(base::Bind(&OfflinePageModel::OnLoadDone
,
65 weak_ptr_factory_
.GetWeakPtr()));
68 OfflinePageModel::~OfflinePageModel() {
71 void OfflinePageModel::Shutdown() {
74 void OfflinePageModel::AddObserver(Observer
* observer
) {
75 observers_
.AddObserver(observer
);
78 void OfflinePageModel::RemoveObserver(Observer
* observer
) {
79 observers_
.RemoveObserver(observer
);
82 void OfflinePageModel::SavePage(const GURL
& url
,
84 scoped_ptr
<OfflinePageArchiver
> archiver
,
85 const SavePageCallback
& callback
) {
87 DCHECK(archiver
.get());
88 archiver
->CreateArchive(base::Bind(&OfflinePageModel::OnCreateArchiveDone
,
89 weak_ptr_factory_
.GetWeakPtr(), url
,
90 bookmark_id
, callback
));
91 pending_archivers_
.push_back(archiver
.Pass());
94 void OfflinePageModel::DeletePageByBookmarkId(
96 const DeletePageCallback
& callback
) {
99 for (const auto& page
: offline_pages_
) {
100 if (page
.bookmark_id
== bookmark_id
) {
101 DeletePage(page
, callback
);
106 callback
.Run(DeletePageResult::NOT_FOUND
);
109 void OfflinePageModel::DeletePage(const OfflinePageItem
& offline_page
,
110 const DeletePageCallback
& callback
) {
113 bool* success
= new bool(false);
114 task_runner_
->PostTaskAndReply(
116 base::Bind(&DeleteArchiveFile
,
117 offline_page
.file_path
,
119 base::Bind(&OfflinePageModel::OnDeleteArchiverFileDone
,
120 weak_ptr_factory_
.GetWeakPtr(),
123 base::Owned(success
)));
126 const std::vector
<OfflinePageItem
>& OfflinePageModel::GetAllPages() const {
128 return offline_pages_
;
131 bool OfflinePageModel::GetPageByBookmarkId(
133 OfflinePageItem
* offline_page
) const {
134 DCHECK(offline_page
);
136 for (const auto& page
: offline_pages_
) {
137 if (page
.bookmark_id
== bookmark_id
) {
138 *offline_page
= page
;
145 OfflinePageMetadataStore
* OfflinePageModel::GetStoreForTesting() {
149 void OfflinePageModel::OnCreateArchiveDone(const GURL
& requested_url
,
151 const SavePageCallback
& callback
,
152 OfflinePageArchiver
* archiver
,
153 ArchiverResult archiver_result
,
155 const base::FilePath
& file_path
,
157 if (requested_url
!= url
) {
158 DVLOG(1) << "Saved URL does not match requested URL.";
159 // TODO(fgorski): We have created an archive for a wrong URL. It should be
160 // deleted from here, once archiver has the right functionality.
161 InformSavePageDone(callback
, SavePageResult::ARCHIVE_CREATION_FAILED
);
162 DeletePendingArchiver(archiver
);
166 if (archiver_result
!= ArchiverResult::SUCCESSFULLY_CREATED
) {
167 SavePageResult result
= ToSavePageResult(archiver_result
);
168 InformSavePageDone(callback
, result
);
169 DeletePendingArchiver(archiver
);
173 OfflinePageItem
offline_page_item(url
, bookmark_id
, file_path
, file_size
,
175 store_
->AddOfflinePage(
177 base::Bind(&OfflinePageModel::OnAddOfflinePageDone
,
178 weak_ptr_factory_
.GetWeakPtr(), archiver
, callback
,
182 void OfflinePageModel::OnAddOfflinePageDone(OfflinePageArchiver
* archiver
,
183 const SavePageCallback
& callback
,
184 const OfflinePageItem
& offline_page
,
186 SavePageResult result
;
188 offline_pages_
.push_back(offline_page
);
189 result
= SavePageResult::SUCCESS
;
191 result
= SavePageResult::STORE_FAILURE
;
193 InformSavePageDone(callback
, result
);
194 DeletePendingArchiver(archiver
);
197 void OfflinePageModel::OnLoadDone(
199 const std::vector
<OfflinePageItem
>& offline_pages
) {
203 // TODO(fgorski): Report the UMA upon failure. Cache should probably start
204 // empty. See if we can do something about it.
206 offline_pages_
= offline_pages
;
208 FOR_EACH_OBSERVER(Observer
, observers_
, OfflinePageModelLoaded(this));
211 void OfflinePageModel::InformSavePageDone(const SavePageCallback
& callback
,
212 SavePageResult result
) {
213 callback
.Run(result
);
216 void OfflinePageModel::DeletePendingArchiver(OfflinePageArchiver
* archiver
) {
217 pending_archivers_
.erase(std::find(
218 pending_archivers_
.begin(), pending_archivers_
.end(), archiver
));
221 void OfflinePageModel::OnDeleteArchiverFileDone(
223 const DeletePageCallback
& callback
,
224 const bool* success
) {
228 callback
.Run(DeletePageResult::DEVICE_FAILURE
);
232 store_
->RemoveOfflinePage(
234 base::Bind(&OfflinePageModel::OnRemoveOfflinePageDone
,
235 weak_ptr_factory_
.GetWeakPtr(), url
, callback
));
238 void OfflinePageModel::OnRemoveOfflinePageDone(
240 const DeletePageCallback
& callback
,
242 // Delete the offline page from the in memory cache regardless of success in
244 for (auto iter
= offline_pages_
.begin();
245 iter
!= offline_pages_
.end();
247 if (iter
->url
== url
) {
248 offline_pages_
.erase(iter
);
254 success
? DeletePageResult::SUCCESS
: DeletePageResult::STORE_FAILURE
);
257 } // namespace offline_pages