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
3 // found in the LICENSE file.
5 #include "components/dom_distiller/core/dom_distiller_service.h"
8 #include "base/message_loop/message_loop.h"
9 #include "components/dom_distiller/core/dom_distiller_store.h"
10 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
11 #include "components/dom_distiller/core/task_tracker.h"
14 namespace dom_distiller {
18 ArticleEntry CreateSkeletonEntryForUrl(const GURL& url) {
19 ArticleEntry skeleton;
20 skeleton.set_entry_id(base::GenerateGUID());
21 ArticleEntryPage* page = skeleton.add_pages();
22 page->set_url(url.spec());
24 DCHECK(IsEntryValid(skeleton));
28 void RunArticleAvailableCallback(
29 const DomDistillerService::ArticleAvailableCallback& article_cb,
30 const ArticleEntry& entry,
31 const DistilledArticleProto* article_proto,
32 bool distillation_succeeded) {
33 article_cb.Run(distillation_succeeded);
38 DomDistillerService::DomDistillerService(
39 scoped_ptr<DomDistillerStoreInterface> store,
40 scoped_ptr<DistillerFactory> distiller_factory)
41 : store_(store.Pass()), distiller_factory_(distiller_factory.Pass()) {}
43 DomDistillerService::~DomDistillerService() {}
45 syncer::SyncableService* DomDistillerService::GetSyncableService() const {
46 return store_->GetSyncableService();
49 const std::string DomDistillerService::AddToList(
51 const ArticleAvailableCallback& article_cb) {
53 const bool is_already_added = store_->GetEntryByUrl(url, &entry);
55 TaskTracker* task_tracker;
56 if (is_already_added) {
57 task_tracker = GetTaskTrackerForEntry(entry);
58 if (task_tracker == NULL) {
59 // Entry is in the store but there is no task tracker. This could
60 // happen when distillation has already completed. For now just return
62 // TODO(shashishekhar): Change this to check if article is available,
63 // An article may not be available for a variety of reasons, e.g.
64 // distillation failure or blobs not available locally.
65 base::MessageLoop::current()->PostTask(FROM_HERE,
66 base::Bind(article_cb, true));
67 return entry.entry_id();
70 task_tracker = GetOrCreateTaskTrackerForUrl(url);
73 if (!article_cb.is_null()) {
74 task_tracker->AddSaveCallback(
75 base::Bind(&RunArticleAvailableCallback, article_cb));
78 if (!is_already_added) {
79 task_tracker->AddSaveCallback(base::Bind(
80 &DomDistillerService::AddDistilledPageToList, base::Unretained(this)));
81 task_tracker->StartDistiller(distiller_factory_.get());
84 return task_tracker->GetEntryId();
87 std::vector<ArticleEntry> DomDistillerService::GetEntries() const {
88 return store_->GetEntries();
91 scoped_ptr<ArticleEntry> DomDistillerService::RemoveEntry(
92 const std::string& entry_id) {
93 scoped_ptr<ArticleEntry> entry(new ArticleEntry);
94 entry->set_entry_id(entry_id);
95 TaskTracker* task_tracker = GetTaskTrackerForEntry(*entry);
96 if (task_tracker != NULL) {
97 task_tracker->CancelSaveCallbacks();
100 if (!store_->GetEntryById(entry_id, entry.get())) {
101 return scoped_ptr<ArticleEntry>();
104 if (store_->RemoveEntry(*entry)) {
107 return scoped_ptr<ArticleEntry>();
110 scoped_ptr<ViewerHandle> DomDistillerService::ViewEntry(
111 ViewRequestDelegate* delegate,
112 const std::string& entry_id) {
114 if (!store_->GetEntryById(entry_id, &entry)) {
115 return scoped_ptr<ViewerHandle>();
118 TaskTracker* task_tracker = GetOrCreateTaskTrackerForEntry(entry);
119 scoped_ptr<ViewerHandle> viewer_handle = task_tracker->AddViewer(delegate);
120 task_tracker->StartDistiller(distiller_factory_.get());
122 return viewer_handle.Pass();
125 scoped_ptr<ViewerHandle> DomDistillerService::ViewUrl(
126 ViewRequestDelegate* delegate,
128 if (!url.is_valid()) {
129 return scoped_ptr<ViewerHandle>();
132 TaskTracker* task_tracker = GetOrCreateTaskTrackerForUrl(url);
133 scoped_ptr<ViewerHandle> viewer_handle = task_tracker->AddViewer(delegate);
134 task_tracker->StartDistiller(distiller_factory_.get());
136 return viewer_handle.Pass();
139 TaskTracker* DomDistillerService::GetOrCreateTaskTrackerForUrl(
142 if (store_->GetEntryByUrl(url, &entry)) {
143 return GetOrCreateTaskTrackerForEntry(entry);
146 for (TaskList::iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
147 if ((*it)->HasUrl(url)) {
152 ArticleEntry skeleton_entry = CreateSkeletonEntryForUrl(url);
153 TaskTracker* task_tracker = CreateTaskTracker(skeleton_entry);
157 TaskTracker* DomDistillerService::GetTaskTrackerForEntry(
158 const ArticleEntry& entry) const {
159 const std::string& entry_id = entry.entry_id();
160 for (TaskList::const_iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
161 if ((*it)->HasEntryId(entry_id)) {
168 TaskTracker* DomDistillerService::GetOrCreateTaskTrackerForEntry(
169 const ArticleEntry& entry) {
170 TaskTracker* task_tracker = GetTaskTrackerForEntry(entry);
171 if (task_tracker == NULL) {
172 task_tracker = CreateTaskTracker(entry);
177 TaskTracker* DomDistillerService::CreateTaskTracker(const ArticleEntry& entry) {
178 TaskTracker::CancelCallback cancel_callback =
179 base::Bind(&DomDistillerService::CancelTask, base::Unretained(this));
180 TaskTracker* tracker = new TaskTracker(entry, cancel_callback);
181 tasks_.push_back(tracker);
185 void DomDistillerService::CancelTask(TaskTracker* task) {
186 TaskList::iterator it = std::find(tasks_.begin(), tasks_.end(), task);
187 if (it != tasks_.end()) {
188 tasks_.weak_erase(it);
189 base::MessageLoop::current()->DeleteSoon(FROM_HERE, task);
193 void DomDistillerService::AddDistilledPageToList(
194 const ArticleEntry& entry,
195 const DistilledArticleProto* article_proto,
196 bool distillation_succeeded) {
197 DCHECK(IsEntryValid(entry));
198 if (distillation_succeeded) {
199 DCHECK(article_proto);
200 DCHECK_GT(article_proto->pages_size(), 0);
201 store_->AddEntry(entry);
202 DCHECK_EQ(article_proto->pages_size(), entry.pages_size());
206 void DomDistillerService::AddObserver(DomDistillerObserver* observer) {
208 store_->AddObserver(observer);
211 void DomDistillerService::RemoveObserver(DomDistillerObserver* observer) {
213 store_->RemoveObserver(observer);
216 } // namespace dom_distiller