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
;
52 OfflinePageModel::OfflinePageModel(
53 scoped_ptr
<OfflinePageMetadataStore
> store
,
54 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
)
55 : store_(store
.Pass()),
57 task_runner_(task_runner
),
58 weak_ptr_factory_(this) {
59 store_
->Load(base::Bind(&OfflinePageModel::OnLoadDone
,
60 weak_ptr_factory_
.GetWeakPtr()));
63 OfflinePageModel::~OfflinePageModel() {
66 void OfflinePageModel::Shutdown() {
69 void OfflinePageModel::AddObserver(Observer
* observer
) {
70 observers_
.AddObserver(observer
);
73 void OfflinePageModel::RemoveObserver(Observer
* observer
) {
74 observers_
.RemoveObserver(observer
);
77 void OfflinePageModel::SavePage(const GURL
& url
,
79 scoped_ptr
<OfflinePageArchiver
> archiver
,
80 const SavePageCallback
& callback
) {
82 DCHECK(archiver
.get());
83 archiver
->CreateArchive(base::Bind(&OfflinePageModel::OnCreateArchiveDone
,
84 weak_ptr_factory_
.GetWeakPtr(), url
,
85 bookmark_id
, callback
));
86 pending_archivers_
.push_back(archiver
.Pass());
89 void OfflinePageModel::DeletePage(const GURL
& url
,
90 const DeletePageCallback
& callback
) {
93 for (const auto& page
: offline_pages_
) {
94 if (page
.url
== url
) {
95 bool* success
= new bool(false);
96 task_runner_
->PostTaskAndReply(
98 base::Bind(&OfflinePageModel::DeleteArchiverFile
,
99 weak_ptr_factory_
.GetWeakPtr(),
102 base::Bind(&OfflinePageModel::OnDeleteArchiverFileDone
,
103 weak_ptr_factory_
.GetWeakPtr(),
106 base::Owned(success
)));
111 callback
.Run(DeletePageResult::NOT_FOUND
);
114 const std::vector
<OfflinePageItem
>& OfflinePageModel::GetAllPages() const {
116 return offline_pages_
;
119 OfflinePageMetadataStore
* OfflinePageModel::GetStoreForTesting() {
123 void OfflinePageModel::OnCreateArchiveDone(const GURL
& requested_url
,
125 const SavePageCallback
& callback
,
126 OfflinePageArchiver
* archiver
,
127 ArchiverResult archiver_result
,
129 const base::FilePath
& file_path
,
131 if (requested_url
!= url
) {
132 DVLOG(1) << "Saved URL does not match requested URL.";
133 // TODO(fgorski): We have created an archive for a wrong URL. It should be
134 // deleted from here, once archiver has the right functionality.
135 InformSavePageDone(callback
, SavePageResult::ARCHIVE_CREATION_FAILED
);
136 DeletePendingArchiver(archiver
);
140 if (archiver_result
!= ArchiverResult::SUCCESSFULLY_CREATED
) {
141 SavePageResult result
= ToSavePageResult(archiver_result
);
142 InformSavePageDone(callback
, result
);
143 DeletePendingArchiver(archiver
);
147 OfflinePageItem
offline_page_item(url
, bookmark_id
, file_path
, file_size
,
149 store_
->AddOfflinePage(
151 base::Bind(&OfflinePageModel::OnAddOfflinePageDone
,
152 weak_ptr_factory_
.GetWeakPtr(), archiver
, callback
,
156 void OfflinePageModel::OnAddOfflinePageDone(OfflinePageArchiver
* archiver
,
157 const SavePageCallback
& callback
,
158 const OfflinePageItem
& offline_page
,
160 SavePageResult result
;
162 offline_pages_
.push_back(offline_page
);
163 result
= SavePageResult::SUCCESS
;
165 result
= SavePageResult::STORE_FAILURE
;
167 InformSavePageDone(callback
, result
);
168 DeletePendingArchiver(archiver
);
171 void OfflinePageModel::OnLoadDone(
173 const std::vector
<OfflinePageItem
>& offline_pages
) {
177 // TODO(fgorski): Report the UMA upon failure. Cache should probably start
178 // empty. See if we can do something about it.
180 offline_pages_
= offline_pages
;
182 FOR_EACH_OBSERVER(Observer
, observers_
, OfflinePageModelLoaded(this));
185 void OfflinePageModel::InformSavePageDone(const SavePageCallback
& callback
,
186 SavePageResult result
) {
187 callback
.Run(result
);
190 void OfflinePageModel::DeletePendingArchiver(OfflinePageArchiver
* archiver
) {
191 pending_archivers_
.erase(std::find(
192 pending_archivers_
.begin(), pending_archivers_
.end(), archiver
));
195 void OfflinePageModel::DeleteArchiverFile(const base::FilePath
& file_path
,
198 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
200 *success
= base::DeleteFile(file_path
, false);
203 void OfflinePageModel::OnDeleteArchiverFileDone(
205 const DeletePageCallback
& callback
,
206 const bool* success
) {
210 callback
.Run(DeletePageResult::DEVICE_FAILURE
);
214 store_
->RemoveOfflinePage(
216 base::Bind(&OfflinePageModel::OnRemoveOfflinePageDone
,
217 weak_ptr_factory_
.GetWeakPtr(), url
, callback
));
220 void OfflinePageModel::OnRemoveOfflinePageDone(
222 const DeletePageCallback
& callback
,
224 // Delete the offline page from the in memory cache regardless of success in
226 for (auto iter
= offline_pages_
.begin();
227 iter
!= offline_pages_
.end();
229 if (iter
->url
== url
) {
230 offline_pages_
.erase(iter
);
236 success
? DeletePageResult::SUCCESS
: DeletePageResult::STORE_FAILURE
);
239 } // namespace offline_pages