OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/dom_distiller/core/task_tracker.h" | 5 #include "components/dom_distiller/core/task_tracker.h" |
6 | 6 |
7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "components/dom_distiller/core/distilled_content_store.h" |
9 #include "components/dom_distiller/core/proto/distilled_article.pb.h" | 10 #include "components/dom_distiller/core/proto/distilled_article.pb.h" |
10 #include "components/dom_distiller/core/proto/distilled_page.pb.h" | 11 #include "components/dom_distiller/core/proto/distilled_page.pb.h" |
11 | 12 |
12 namespace dom_distiller { | 13 namespace dom_distiller { |
13 | 14 |
14 ViewerHandle::ViewerHandle(CancelCallback callback) | 15 ViewerHandle::ViewerHandle(CancelCallback callback) |
15 : cancel_callback_(callback) {} | 16 : cancel_callback_(callback) {} |
16 | 17 |
17 ViewerHandle::~ViewerHandle() { | 18 ViewerHandle::~ViewerHandle() { |
18 if (!cancel_callback_.is_null()) { | 19 if (!cancel_callback_.is_null()) { |
19 cancel_callback_.Run(); | 20 cancel_callback_.Run(); |
20 } | 21 } |
21 } | 22 } |
22 | 23 |
23 TaskTracker::TaskTracker(const ArticleEntry& entry, CancelCallback callback) | 24 TaskTracker::TaskTracker(const ArticleEntry& entry, |
| 25 CancelCallback callback, |
| 26 DistilledContentStore* content_store) |
24 : cancel_callback_(callback), | 27 : cancel_callback_(callback), |
| 28 content_store_(content_store), |
| 29 blob_fetcher_running_(false), |
25 entry_(entry), | 30 entry_(entry), |
26 distilled_article_(), | 31 distilled_article_(), |
27 content_ready_(false), | 32 content_ready_(false), |
28 destruction_allowed_(true), | 33 destruction_allowed_(true), |
29 weak_ptr_factory_(this) {} | 34 weak_ptr_factory_(this) {} |
30 | 35 |
31 TaskTracker::~TaskTracker() { | 36 TaskTracker::~TaskTracker() { |
32 DCHECK(destruction_allowed_); | 37 DCHECK(destruction_allowed_); |
33 DCHECK(viewers_.empty()); | 38 DCHECK(viewers_.empty()); |
34 } | 39 } |
35 | 40 |
36 void TaskTracker::StartDistiller(DistillerFactory* factory) { | 41 void TaskTracker::StartDistiller(DistillerFactory* factory) { |
37 if (distiller_) { | 42 if (distiller_) { |
38 return; | 43 return; |
39 } | 44 } |
40 if (entry_.pages_size() == 0) { | 45 if (entry_.pages_size() == 0) { |
41 return; | 46 return; |
42 } | 47 } |
43 | |
44 GURL url(entry_.pages(0).url()); | 48 GURL url(entry_.pages(0).url()); |
45 DCHECK(url.is_valid()); | 49 DCHECK(url.is_valid()); |
46 | 50 |
47 distiller_ = factory->CreateDistiller(); | 51 distiller_ = factory->CreateDistiller(); |
48 distiller_->DistillPage(url, | 52 distiller_->DistillPage(url, |
49 base::Bind(&TaskTracker::OnDistillerFinished, | 53 base::Bind(&TaskTracker::OnDistillerFinished, |
50 weak_ptr_factory_.GetWeakPtr()), | 54 weak_ptr_factory_.GetWeakPtr()), |
51 base::Bind(&TaskTracker::OnArticleDistillationUpdated, | 55 base::Bind(&TaskTracker::OnArticleDistillationUpdated, |
52 weak_ptr_factory_.GetWeakPtr())); | 56 weak_ptr_factory_.GetWeakPtr())); |
53 } | 57 } |
54 | 58 |
55 void TaskTracker::StartBlobFetcher() { | 59 void TaskTracker::StartBlobFetcher() { |
56 // TODO(cjhopman): There needs to be some local storage for the distilled | 60 if (content_store_) { |
57 // blob. When that happens, this should start some task to fetch the blob for | 61 content_store_->LoadContent(entry_, |
58 // |entry_| and asynchronously notify |this| when it is done. | 62 base::Bind(&TaskTracker::OnBlobFetched, |
| 63 weak_ptr_factory_.GetWeakPtr())); |
| 64 } |
59 } | 65 } |
60 | 66 |
61 void TaskTracker::AddSaveCallback(const SaveCallback& callback) { | 67 void TaskTracker::AddSaveCallback(const SaveCallback& callback) { |
62 DCHECK(!callback.is_null()); | 68 DCHECK(!callback.is_null()); |
63 save_callbacks_.push_back(callback); | 69 save_callbacks_.push_back(callback); |
64 if (content_ready_) { | 70 if (content_ready_) { |
65 // Distillation for this task has already completed, and so it can be | 71 // Distillation for this task has already completed, and so it can be |
66 // immediately saved. | 72 // immediately saved. |
67 ScheduleSaveCallbacks(true); | 73 ScheduleSaveCallbacks(true); |
68 } | 74 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 MaybeCancel(); | 110 MaybeCancel(); |
105 } | 111 } |
106 } | 112 } |
107 | 113 |
108 void TaskTracker::MaybeCancel() { | 114 void TaskTracker::MaybeCancel() { |
109 if (!save_callbacks_.empty() || !viewers_.empty()) { | 115 if (!save_callbacks_.empty() || !viewers_.empty()) { |
110 // There's still work to be done. | 116 // There's still work to be done. |
111 return; | 117 return; |
112 } | 118 } |
113 | 119 |
| 120 CancelPendingSources(); |
| 121 |
114 base::AutoReset<bool> dont_delete_this_in_callback(&destruction_allowed_, | 122 base::AutoReset<bool> dont_delete_this_in_callback(&destruction_allowed_, |
115 false); | 123 false); |
116 cancel_callback_.Run(this); | 124 cancel_callback_.Run(this); |
117 } | 125 } |
118 | 126 |
119 void TaskTracker::CancelSaveCallbacks() { ScheduleSaveCallbacks(false); } | 127 void TaskTracker::CancelSaveCallbacks() { ScheduleSaveCallbacks(false); } |
120 | 128 |
121 void TaskTracker::ScheduleSaveCallbacks(bool distillation_succeeded) { | 129 void TaskTracker::ScheduleSaveCallbacks(bool distillation_succeeded) { |
122 base::MessageLoop::current()->PostTask( | 130 base::MessageLoop::current()->PostTask( |
123 FROM_HERE, | 131 FROM_HERE, |
124 base::Bind(&TaskTracker::DoSaveCallbacks, | 132 base::Bind(&TaskTracker::DoSaveCallbacks, |
125 weak_ptr_factory_.GetWeakPtr(), | 133 weak_ptr_factory_.GetWeakPtr(), |
126 distillation_succeeded)); | 134 distillation_succeeded)); |
127 } | 135 } |
128 | 136 |
129 void TaskTracker::DoSaveCallbacks(bool distillation_succeeded) { | 137 void TaskTracker::OnDistillerFinished( |
| 138 scoped_ptr<DistilledArticleProto> distilled_article) { |
| 139 if (content_ready_) { |
| 140 return; |
| 141 } |
| 142 |
| 143 DistilledArticleReady(distilled_article.Pass()); |
| 144 if (content_ready_) { |
| 145 AddDistilledContentToStore(*distilled_article_); |
| 146 } |
| 147 |
| 148 ContentSourceFinished(); |
| 149 } |
| 150 |
| 151 void TaskTracker::CancelPendingSources() { |
| 152 base::MessageLoop::current()->DeleteSoon(FROM_HERE, distiller_.release()); |
| 153 } |
| 154 |
| 155 void TaskTracker::OnBlobFetched( |
| 156 bool success, |
| 157 scoped_ptr<DistilledArticleProto> distilled_article) { |
| 158 blob_fetcher_running_ = false; |
| 159 |
| 160 if (content_ready_) { |
| 161 return; |
| 162 } |
| 163 |
| 164 DistilledArticleReady(distilled_article.Pass()); |
| 165 |
| 166 ContentSourceFinished(); |
| 167 } |
| 168 |
| 169 bool TaskTracker::IsAnySourceRunning() const { |
| 170 return distiller_ || blob_fetcher_running_; |
| 171 } |
| 172 |
| 173 void TaskTracker::ContentSourceFinished() { |
| 174 if (content_ready_) { |
| 175 CancelPendingSources(); |
| 176 } else if (!IsAnySourceRunning()) { |
| 177 distilled_article_.reset(new DistilledArticleProto()); |
| 178 NotifyViewersAndCallbacks(); |
| 179 } |
| 180 } |
| 181 |
| 182 void TaskTracker::DistilledArticleReady( |
| 183 scoped_ptr<DistilledArticleProto> distilled_article) { |
| 184 DCHECK(!content_ready_); |
| 185 |
| 186 if (distilled_article->pages_size() == 0) { |
| 187 return; |
| 188 } |
| 189 |
| 190 content_ready_ = true; |
| 191 |
| 192 distilled_article_ = distilled_article.Pass(); |
| 193 entry_.set_title(distilled_article_->title()); |
| 194 entry_.clear_pages(); |
| 195 for (int i = 0; i < distilled_article_->pages_size(); ++i) { |
| 196 sync_pb::ArticlePage* page = entry_.add_pages(); |
| 197 page->set_url(distilled_article_->pages(i).url()); |
| 198 } |
| 199 |
| 200 NotifyViewersAndCallbacks(); |
| 201 } |
| 202 |
| 203 void TaskTracker::NotifyViewersAndCallbacks() { |
| 204 for (size_t i = 0; i < viewers_.size(); ++i) { |
| 205 NotifyViewer(viewers_[i]); |
| 206 } |
| 207 |
| 208 // Already inside a callback run SaveCallbacks directly. |
| 209 DoSaveCallbacks(content_ready_); |
| 210 } |
| 211 |
| 212 void TaskTracker::NotifyViewer(ViewRequestDelegate* delegate) { |
| 213 delegate->OnArticleReady(distilled_article_.get()); |
| 214 } |
| 215 |
| 216 void TaskTracker::DoSaveCallbacks(bool success) { |
130 if (!save_callbacks_.empty()) { | 217 if (!save_callbacks_.empty()) { |
131 for (size_t i = 0; i < save_callbacks_.size(); ++i) { | 218 for (size_t i = 0; i < save_callbacks_.size(); ++i) { |
132 DCHECK(!save_callbacks_[i].is_null()); | 219 DCHECK(!save_callbacks_[i].is_null()); |
133 save_callbacks_[i].Run( | 220 save_callbacks_[i].Run( |
134 entry_, distilled_article_.get(), distillation_succeeded); | 221 entry_, distilled_article_.get(), success); |
135 } | 222 } |
136 | 223 |
137 save_callbacks_.clear(); | 224 save_callbacks_.clear(); |
138 MaybeCancel(); | 225 MaybeCancel(); |
139 } | 226 } |
140 } | 227 } |
141 | 228 |
142 void TaskTracker::NotifyViewer(ViewRequestDelegate* delegate) { | |
143 DCHECK(content_ready_); | |
144 delegate->OnArticleReady(distilled_article_.get()); | |
145 } | |
146 | |
147 void TaskTracker::OnDistillerFinished( | |
148 scoped_ptr<DistilledArticleProto> distilled_article) { | |
149 OnDistilledArticleReady(distilled_article.Pass()); | |
150 } | |
151 | |
152 void TaskTracker::OnDistilledArticleReady( | |
153 scoped_ptr<DistilledArticleProto> distilled_article) { | |
154 distilled_article_ = distilled_article.Pass(); | |
155 bool distillation_successful = false; | |
156 if (distilled_article_->pages_size() > 0) { | |
157 distillation_successful = true; | |
158 entry_.set_title(distilled_article_->title()); | |
159 // Reset the pages. | |
160 entry_.clear_pages(); | |
161 for (int i = 0; i < distilled_article_->pages_size(); ++i) { | |
162 sync_pb::ArticlePage* page = entry_.add_pages(); | |
163 page->set_url(distilled_article_->pages(i).url()); | |
164 } | |
165 } | |
166 | |
167 content_ready_ = true; | |
168 | |
169 for (size_t i = 0; i < viewers_.size(); ++i) { | |
170 NotifyViewer(viewers_[i]); | |
171 } | |
172 | |
173 // Already inside a callback run SaveCallbacks directly. | |
174 DoSaveCallbacks(distillation_successful); | |
175 } | |
176 | |
177 void TaskTracker::OnArticleDistillationUpdated( | 229 void TaskTracker::OnArticleDistillationUpdated( |
178 const ArticleDistillationUpdate& article_update) { | 230 const ArticleDistillationUpdate& article_update) { |
179 for (size_t i = 0; i < viewers_.size(); ++i) { | 231 for (size_t i = 0; i < viewers_.size(); ++i) { |
180 viewers_[i]->OnArticleUpdated(article_update); | 232 viewers_[i]->OnArticleUpdated(article_update); |
181 } | 233 } |
182 } | 234 } |
183 | 235 |
| 236 void TaskTracker::AddDistilledContentToStore( |
| 237 const DistilledArticleProto& content) { |
| 238 if (content_store_) { |
| 239 content_store_->SaveContent( |
| 240 entry_, content, DistilledContentStore::SaveCallback()); |
| 241 } |
| 242 } |
| 243 |
| 244 |
184 } // namespace dom_distiller | 245 } // namespace dom_distiller |
OLD | NEW |