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/task_tracker.h"
13 namespace dom_distiller {
17 ArticleEntry CreateSkeletonEntryForUrl(const GURL& url) {
18 ArticleEntry skeleton;
19 skeleton.set_entry_id(base::GenerateGUID());
20 ArticleEntryPage* page = skeleton.add_pages();
21 page->set_url(url.spec());
23 DCHECK(IsEntryValid(skeleton));
27 void RunArticleAvailableCallback(
28 const DomDistillerService::ArticleAvailableCallback& article_cb,
29 const ArticleEntry& entry,
30 DistilledPageProto* proto,
31 bool distillation_succeeded) {
32 article_cb.Run(distillation_succeeded);
37 DomDistillerService::DomDistillerService(
38 scoped_ptr<DomDistillerStoreInterface> store,
39 scoped_ptr<DistillerFactory> distiller_factory)
40 : store_(store.Pass()), distiller_factory_(distiller_factory.Pass()) {}
42 DomDistillerService::~DomDistillerService() {}
44 syncer::SyncableService* DomDistillerService::GetSyncableService() const {
45 return store_->GetSyncableService();
48 const std::string DomDistillerService::AddToList(
50 const ArticleAvailableCallback& article_cb) {
52 const bool is_already_added = store_->GetEntryByUrl(url, &entry);
54 TaskTracker* task_tracker;
55 if (is_already_added) {
56 task_tracker = GetTaskTrackerForEntry(entry);
57 if (task_tracker == NULL) {
58 // Entry is in the store but there is no task tracker. This could
59 // happen when distillation has already completed. For now just return
61 // TODO(shashishekhar): Change this to check if article is available,
62 // An article may not be available for a variety of reasons, e.g.
63 // distillation failure or blobs not available locally.
64 base::MessageLoop::current()->PostTask(FROM_HERE,
65 base::Bind(article_cb, true));
66 return entry.entry_id();
69 task_tracker = GetOrCreateTaskTrackerForUrl(url);
72 if (!article_cb.is_null()) {
73 task_tracker->AddSaveCallback(
74 base::Bind(&RunArticleAvailableCallback, article_cb));
77 if (!is_already_added) {
78 task_tracker->AddSaveCallback(base::Bind(
79 &DomDistillerService::AddDistilledPageToList, base::Unretained(this)));
80 task_tracker->StartDistiller(distiller_factory_.get());
83 return task_tracker->GetEntryId();
86 std::vector<ArticleEntry> DomDistillerService::GetEntries() const {
87 return store_->GetEntries();
90 scoped_ptr<ArticleEntry> DomDistillerService::RemoveEntry(
91 const std::string& entry_id) {
92 scoped_ptr<ArticleEntry> entry(new ArticleEntry);
93 if (!store_->GetEntryById(entry_id, entry.get())) {
94 return scoped_ptr<ArticleEntry>();
97 TaskTracker* task_tracker = GetTaskTrackerForEntry(*entry);
98 if (task_tracker != NULL) {
99 task_tracker->CancelSaveCallbacks();
102 if (store_->RemoveEntry(*entry)) {
105 return scoped_ptr<ArticleEntry>();
108 scoped_ptr<ViewerHandle> DomDistillerService::ViewEntry(
109 ViewRequestDelegate* delegate,
110 const std::string& entry_id) {
112 if (!store_->GetEntryById(entry_id, &entry)) {
113 return scoped_ptr<ViewerHandle>();
116 TaskTracker* task_tracker = GetOrCreateTaskTrackerForEntry(entry);
117 scoped_ptr<ViewerHandle> viewer_handle = task_tracker->AddViewer(delegate);
118 task_tracker->StartDistiller(distiller_factory_.get());
120 return viewer_handle.Pass();
123 scoped_ptr<ViewerHandle> DomDistillerService::ViewUrl(
124 ViewRequestDelegate* delegate,
126 if (!url.is_valid()) {
127 return scoped_ptr<ViewerHandle>();
130 TaskTracker* task_tracker = GetOrCreateTaskTrackerForUrl(url);
131 scoped_ptr<ViewerHandle> viewer_handle = task_tracker->AddViewer(delegate);
132 task_tracker->StartDistiller(distiller_factory_.get());
134 return viewer_handle.Pass();
137 TaskTracker* DomDistillerService::GetOrCreateTaskTrackerForUrl(
140 if (store_->GetEntryByUrl(url, &entry)) {
141 return GetOrCreateTaskTrackerForEntry(entry);
144 for (TaskList::iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
145 if ((*it)->HasUrl(url)) {
150 ArticleEntry skeleton_entry = CreateSkeletonEntryForUrl(url);
151 TaskTracker* task_tracker = CreateTaskTracker(skeleton_entry);
152 store_->AddEntry(skeleton_entry);
156 TaskTracker* DomDistillerService::GetTaskTrackerForEntry(
157 const ArticleEntry& entry) const {
158 const std::string& entry_id = entry.entry_id();
159 for (TaskList::const_iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
160 if ((*it)->HasEntryId(entry_id)) {
167 TaskTracker* DomDistillerService::GetOrCreateTaskTrackerForEntry(
168 const ArticleEntry& entry) {
169 TaskTracker* task_tracker = GetTaskTrackerForEntry(entry);
170 if (task_tracker == NULL) {
171 task_tracker = CreateTaskTracker(entry);
176 TaskTracker* DomDistillerService::CreateTaskTracker(const ArticleEntry& entry) {
177 TaskTracker::CancelCallback cancel_callback =
178 base::Bind(&DomDistillerService::CancelTask, base::Unretained(this));
179 TaskTracker* tracker = new TaskTracker(entry, cancel_callback);
180 tasks_.push_back(tracker);
184 void DomDistillerService::CancelTask(TaskTracker* task) {
185 TaskList::iterator it = std::find(tasks_.begin(), tasks_.end(), task);
186 if (it != tasks_.end()) {
187 tasks_.weak_erase(it);
188 base::MessageLoop::current()->DeleteSoon(FROM_HERE, task);
192 void DomDistillerService::AddDistilledPageToList(const ArticleEntry& entry,
193 DistilledPageProto* proto,
194 bool distillation_succeeded) {
195 DCHECK(IsEntryValid(entry));
196 if (distillation_succeeded) {
198 store_->UpdateEntry(entry);
202 void DomDistillerService::AddObserver(DomDistillerObserver* observer) {
204 store_->AddObserver(observer);
207 void DomDistillerService::RemoveObserver(DomDistillerObserver* observer) {
209 store_->RemoveObserver(observer);
212 } // namespace dom_distiller