Chromium Code Reviews| Index: components/dom_distiller/core/dom_distiller_store.cc |
| diff --git a/components/dom_distiller/core/dom_distiller_store.cc b/components/dom_distiller/core/dom_distiller_store.cc |
| index 8a3aad588139ad4f1082b11d26a44b5b27e287fd..72e480f4127c8fba819d97586f816790faef942e 100644 |
| --- a/components/dom_distiller/core/dom_distiller_store.cc |
| +++ b/components/dom_distiller/core/dom_distiller_store.cc |
| @@ -6,6 +6,7 @@ |
| #include "base/bind.h" |
| #include "base/logging.h" |
| +#include "base/message_loop/message_loop.h" |
| #include "components/dom_distiller/core/article_entry.h" |
| #include "sync/api/sync_change.h" |
| #include "sync/protocol/article_specifics.pb.h" |
| @@ -29,6 +30,7 @@ DomDistillerStore::DomDistillerStore( |
| const base::FilePath& database_dir) |
| : database_(database.Pass()), |
| database_loaded_(false), |
| + attachment_store_(syncer::AttachmentStore::CreateInMemoryStore()), |
| weak_ptr_factory_(this) { |
| database_->Init(database_dir, base::Bind(&DomDistillerStore::OnDatabaseInit, |
| weak_ptr_factory_.GetWeakPtr())); |
| @@ -40,6 +42,7 @@ DomDistillerStore::DomDistillerStore( |
| const base::FilePath& database_dir) |
| : database_(database.Pass()), |
| database_loaded_(false), |
| + attachment_store_(syncer::AttachmentStore::CreateInMemoryStore()), |
| model_(initial_data), |
| weak_ptr_factory_(this) { |
| database_->Init(database_dir, base::Bind(&DomDistillerStore::OnDatabaseInit, |
| @@ -62,6 +65,119 @@ bool DomDistillerStore::GetEntryByUrl(const GURL& url, ArticleEntry* entry) { |
| return model_.GetEntryByUrl(url, entry); |
| } |
| +void DomDistillerStore::UpdateAttachments( |
| + const std::string& entry_id, |
| + scoped_ptr<ArticleAttachmentsData> attachments_data, |
| + const UpdateAttachmentsCallback& callback) { |
| + if (!GetEntryById(entry_id, nullptr)) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(callback, false)); |
| + } |
| + |
| + scoped_ptr<sync_pb::ArticleAttachments> article_attachments( |
| + new sync_pb::ArticleAttachments()); |
| + syncer::AttachmentList attachment_list; |
| + attachments_data->CreateSyncAttachments(&attachment_list, |
| + article_attachments.get()); |
| + |
| + attachment_store_->Write( |
| + attachment_list, |
| + base::Bind(&DomDistillerStore::OnAttachmentsWrite, |
| + weak_ptr_factory_.GetWeakPtr(), entry_id, |
| + base::Passed(&article_attachments), callback)); |
| +} |
| + |
| +void DomDistillerStore::OnAttachmentsWrite( |
| + const std::string& entry_id, |
| + scoped_ptr<sync_pb::ArticleAttachments> article_attachments, |
| + const UpdateAttachmentsCallback& callback, |
| + const syncer::AttachmentStore::Result& result) { |
| + bool success = false; |
| + switch (result) { |
| + case syncer::AttachmentStore::UNSPECIFIED_ERROR: |
| + break; |
| + case syncer::AttachmentStore::SUCCESS: |
| + success = true; |
| + break; |
| + } |
| + |
| + if (success) { |
| + ArticleEntry entry; |
| + bool has_entry = GetEntryById(entry_id, &entry); |
| + if (!has_entry) { |
| + success = false; |
| + attachment_store_->Drop(GetAttachmentIds(*article_attachments), |
| + syncer::AttachmentStore::DropCallback()); |
| + } else { |
| + if (entry.has_attachments()) { |
| + attachment_store_->Drop(GetAttachmentIds(entry.attachments()), |
| + syncer::AttachmentStore::DropCallback()); |
| + } |
| + entry.set_allocated_attachments(article_attachments.release()); |
| + |
| + SyncChangeList changes_to_apply; |
| + changes_to_apply.push_back(SyncChange( |
| + FROM_HERE, SyncChange::ACTION_UPDATE, CreateLocalData(entry))); |
| + |
| + SyncChangeList changes_applied; |
| + SyncChangeList changes_missing; |
| + |
| + ApplyChangesToModel(changes_to_apply, &changes_applied, &changes_missing); |
| + |
| + DCHECK_EQ(size_t(0), changes_missing.size()); |
| + DCHECK_EQ(size_t(1), changes_applied.size()); |
| + |
| + ApplyChangesToSync(FROM_HERE, changes_applied); |
| + ApplyChangesToDatabase(changes_applied); |
| + } |
| + } |
| + base::MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(callback, success)); |
| +} |
| + |
| +void DomDistillerStore::GetAttachments( |
| + const std::string& entry_id, |
| + const GetAttachmentsCallback& callback) { |
| + ArticleEntry entry; |
| + if (!model_.GetEntryById(entry_id, &entry) |
| + || !entry.has_attachments()) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, base::Bind(callback, false, nullptr)); |
| + return; |
| + } |
| + |
| + // TODO(cjhopman): This should use GetOrDownloadAttachments() once there is a |
| + // feasible way to use that. |
| + attachment_store_->Read(GetAttachmentIds(entry.attachments()), |
| + base::Bind(&DomDistillerStore::OnAttachmentsRead, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + entry.attachments(), callback)); |
| +} |
| + |
| +void DomDistillerStore::OnAttachmentsRead( |
| + const sync_pb::ArticleAttachments& attachments_proto, |
| + const GetAttachmentsCallback& callback, |
| + const syncer::AttachmentStore::Result& result, |
| + scoped_ptr<syncer::AttachmentMap> attachments, |
| + scoped_ptr<syncer::AttachmentIdList> missing) { |
| + bool success = false; |
| + switch (result) { |
| + case syncer::AttachmentStore::UNSPECIFIED_ERROR: |
| + break; |
| + case syncer::AttachmentStore::SUCCESS: |
| + success = missing->empty(); |
|
pavely
2014/11/17 19:09:00
Minor comment: if result is SUCCESS then |missing|
cjhopman
2014/11/18 20:57:45
Done.
|
| + break; |
| + } |
| + scoped_ptr<ArticleAttachmentsData> attachments_data; |
| + if (success) { |
| + attachments_data = ArticleAttachmentsData::GetFromAttachmentMap( |
| + attachments_proto, *attachments); |
| + } |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(callback, success, base::Passed(&attachments_data))); |
| +} |
| + |
| bool DomDistillerStore::AddEntry(const ArticleEntry& entry) { |
| return ChangeEntry(entry, SyncChange::ACTION_ADD); |
| } |
| @@ -74,6 +190,22 @@ bool DomDistillerStore::RemoveEntry(const ArticleEntry& entry) { |
| return ChangeEntry(entry, SyncChange::ACTION_DELETE); |
| } |
| +namespace { |
| + |
| +bool VerifyAttachmentsUnchanged(const ArticleEntry& entry, |
| + const DomDistillerModel& model) { |
| + ArticleEntry currentEntry; |
| + model.GetEntryById(entry.entry_id(), ¤tEntry); |
| + DCHECK_EQ(currentEntry.has_attachments(), entry.has_attachments()); |
| + if (currentEntry.has_attachments()) { |
| + DCHECK_EQ(currentEntry.attachments().SerializeAsString(), |
| + entry.attachments().SerializeAsString()); |
| + } |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| bool DomDistillerStore::ChangeEntry(const ArticleEntry& entry, |
| SyncChange::SyncChangeType changeType) { |
| if (!database_loaded_) { |
| @@ -86,6 +218,7 @@ bool DomDistillerStore::ChangeEntry(const ArticleEntry& entry, |
| DVLOG(1) << "Already have entry with id " << entry.entry_id() << "."; |
| return false; |
| } |
| + DCHECK(VerifyAttachmentsUnchanged(entry, model_)); |
| } else if (changeType != SyncChange::ACTION_ADD) { |
| DVLOG(1) << "No entry with id " << entry.entry_id() << " found."; |
| return false; |