root/components/dom_distiller/core/dom_distiller_service.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CreateSkeletonEntryForUrl
  2. RunArticleAvailableCallback
  3. distiller_factory_
  4. GetSyncableService
  5. AddToList
  6. GetEntries
  7. RemoveEntry
  8. ViewEntry
  9. ViewUrl
  10. GetOrCreateTaskTrackerForUrl
  11. GetTaskTrackerForEntry
  12. GetOrCreateTaskTrackerForEntry
  13. CreateTaskTracker
  14. CancelTask
  15. AddDistilledPageToList
  16. AddObserver
  17. RemoveObserver

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/dom_distiller/core/dom_distiller_service.h"

#include "base/guid.h"
#include "base/message_loop/message_loop.h"
#include "components/dom_distiller/core/dom_distiller_store.h"
#include "components/dom_distiller/core/proto/distilled_article.pb.h"
#include "components/dom_distiller/core/task_tracker.h"
#include "url/gurl.h"

namespace dom_distiller {

namespace {

ArticleEntry CreateSkeletonEntryForUrl(const GURL& url) {
  ArticleEntry skeleton;
  skeleton.set_entry_id(base::GenerateGUID());
  ArticleEntryPage* page = skeleton.add_pages();
  page->set_url(url.spec());

  DCHECK(IsEntryValid(skeleton));
  return skeleton;
}

void RunArticleAvailableCallback(
    const DomDistillerService::ArticleAvailableCallback& article_cb,
    const ArticleEntry& entry,
    const DistilledArticleProto* article_proto,
    bool distillation_succeeded) {
  article_cb.Run(distillation_succeeded);
}

}  // namespace

DomDistillerService::DomDistillerService(
    scoped_ptr<DomDistillerStoreInterface> store,
    scoped_ptr<DistillerFactory> distiller_factory)
    : store_(store.Pass()), distiller_factory_(distiller_factory.Pass()) {}

DomDistillerService::~DomDistillerService() {}

syncer::SyncableService* DomDistillerService::GetSyncableService() const {
  return store_->GetSyncableService();
}

const std::string DomDistillerService::AddToList(
    const GURL& url,
    const ArticleAvailableCallback& article_cb) {
  ArticleEntry entry;
  const bool is_already_added = store_->GetEntryByUrl(url, &entry);

  TaskTracker* task_tracker;
  if (is_already_added) {
    task_tracker = GetTaskTrackerForEntry(entry);
    if (task_tracker == NULL) {
      // Entry is in the store but there is no task tracker. This could
      // happen when distillation has already completed. For now just return
      // true.
      // TODO(shashishekhar): Change this to check if article is available,
      // An article may not be available for a variety of reasons, e.g.
      // distillation failure or blobs not available locally.
      base::MessageLoop::current()->PostTask(FROM_HERE,
                                             base::Bind(article_cb, true));
      return entry.entry_id();
    }
  } else {
    task_tracker = GetOrCreateTaskTrackerForUrl(url);
  }

  if (!article_cb.is_null()) {
    task_tracker->AddSaveCallback(
        base::Bind(&RunArticleAvailableCallback, article_cb));
  }

  if (!is_already_added) {
    task_tracker->AddSaveCallback(base::Bind(
        &DomDistillerService::AddDistilledPageToList, base::Unretained(this)));
    task_tracker->StartDistiller(distiller_factory_.get());
  }

  return task_tracker->GetEntryId();
}

std::vector<ArticleEntry> DomDistillerService::GetEntries() const {
  return store_->GetEntries();
}

scoped_ptr<ArticleEntry> DomDistillerService::RemoveEntry(
    const std::string& entry_id) {
  scoped_ptr<ArticleEntry> entry(new ArticleEntry);
  entry->set_entry_id(entry_id);
  TaskTracker* task_tracker = GetTaskTrackerForEntry(*entry);
  if (task_tracker != NULL) {
    task_tracker->CancelSaveCallbacks();
  }

  if (!store_->GetEntryById(entry_id, entry.get())) {
    return scoped_ptr<ArticleEntry>();
  }

  if (store_->RemoveEntry(*entry)) {
    return entry.Pass();
  }
  return scoped_ptr<ArticleEntry>();
}

scoped_ptr<ViewerHandle> DomDistillerService::ViewEntry(
    ViewRequestDelegate* delegate,
    const std::string& entry_id) {
  ArticleEntry entry;
  if (!store_->GetEntryById(entry_id, &entry)) {
    return scoped_ptr<ViewerHandle>();
  }

  TaskTracker* task_tracker = GetOrCreateTaskTrackerForEntry(entry);
  scoped_ptr<ViewerHandle> viewer_handle = task_tracker->AddViewer(delegate);
  task_tracker->StartDistiller(distiller_factory_.get());

  return viewer_handle.Pass();
}

scoped_ptr<ViewerHandle> DomDistillerService::ViewUrl(
    ViewRequestDelegate* delegate,
    const GURL& url) {
  if (!url.is_valid()) {
    return scoped_ptr<ViewerHandle>();
  }

  TaskTracker* task_tracker = GetOrCreateTaskTrackerForUrl(url);
  scoped_ptr<ViewerHandle> viewer_handle = task_tracker->AddViewer(delegate);
  task_tracker->StartDistiller(distiller_factory_.get());

  return viewer_handle.Pass();
}

TaskTracker* DomDistillerService::GetOrCreateTaskTrackerForUrl(
    const GURL& url) {
  ArticleEntry entry;
  if (store_->GetEntryByUrl(url, &entry)) {
    return GetOrCreateTaskTrackerForEntry(entry);
  }

  for (TaskList::iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
    if ((*it)->HasUrl(url)) {
      return *it;
    }
  }

  ArticleEntry skeleton_entry = CreateSkeletonEntryForUrl(url);
  TaskTracker* task_tracker = CreateTaskTracker(skeleton_entry);
  return task_tracker;
}

TaskTracker* DomDistillerService::GetTaskTrackerForEntry(
    const ArticleEntry& entry) const {
  const std::string& entry_id = entry.entry_id();
  for (TaskList::const_iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
    if ((*it)->HasEntryId(entry_id)) {
      return *it;
    }
  }
  return NULL;
}

TaskTracker* DomDistillerService::GetOrCreateTaskTrackerForEntry(
    const ArticleEntry& entry) {
  TaskTracker* task_tracker = GetTaskTrackerForEntry(entry);
  if (task_tracker == NULL) {
    task_tracker = CreateTaskTracker(entry);
  }
  return task_tracker;
}

TaskTracker* DomDistillerService::CreateTaskTracker(const ArticleEntry& entry) {
  TaskTracker::CancelCallback cancel_callback =
      base::Bind(&DomDistillerService::CancelTask, base::Unretained(this));
  TaskTracker* tracker = new TaskTracker(entry, cancel_callback);
  tasks_.push_back(tracker);
  return tracker;
}

void DomDistillerService::CancelTask(TaskTracker* task) {
  TaskList::iterator it = std::find(tasks_.begin(), tasks_.end(), task);
  if (it != tasks_.end()) {
    tasks_.weak_erase(it);
    base::MessageLoop::current()->DeleteSoon(FROM_HERE, task);
  }
}

void DomDistillerService::AddDistilledPageToList(
    const ArticleEntry& entry,
    const DistilledArticleProto* article_proto,
    bool distillation_succeeded) {
  DCHECK(IsEntryValid(entry));
  if (distillation_succeeded) {
    DCHECK(article_proto);
    DCHECK_GT(article_proto->pages_size(), 0);
    store_->AddEntry(entry);
    DCHECK_EQ(article_proto->pages_size(), entry.pages_size());
  }
}

void DomDistillerService::AddObserver(DomDistillerObserver* observer) {
  DCHECK(observer);
  store_->AddObserver(observer);
}

void DomDistillerService::RemoveObserver(DomDistillerObserver* observer) {
  DCHECK(observer);
  store_->RemoveObserver(observer);
}

}  // namespace dom_distiller

/* [<][>][^][v][top][bottom][index][help] */