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/dom_distiller_store.h" | 5 #include "components/dom_distiller/core/dom_distiller_store.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop/message_loop.h" | |
9 #include "components/dom_distiller/core/article_entry.h" | 10 #include "components/dom_distiller/core/article_entry.h" |
10 #include "sync/api/sync_change.h" | 11 #include "sync/api/sync_change.h" |
11 #include "sync/protocol/article_specifics.pb.h" | 12 #include "sync/protocol/article_specifics.pb.h" |
12 #include "sync/protocol/sync.pb.h" | 13 #include "sync/protocol/sync.pb.h" |
13 | 14 |
14 using leveldb_proto::ProtoDatabase; | 15 using leveldb_proto::ProtoDatabase; |
15 using sync_pb::ArticleSpecifics; | 16 using sync_pb::ArticleSpecifics; |
16 using sync_pb::EntitySpecifics; | 17 using sync_pb::EntitySpecifics; |
17 using syncer::ModelType; | 18 using syncer::ModelType; |
18 using syncer::SyncChange; | 19 using syncer::SyncChange; |
19 using syncer::SyncChangeList; | 20 using syncer::SyncChangeList; |
20 using syncer::SyncData; | 21 using syncer::SyncData; |
21 using syncer::SyncDataList; | 22 using syncer::SyncDataList; |
22 using syncer::SyncError; | 23 using syncer::SyncError; |
23 using syncer::SyncMergeResult; | 24 using syncer::SyncMergeResult; |
24 | 25 |
25 namespace dom_distiller { | 26 namespace dom_distiller { |
26 | 27 |
27 DomDistillerStore::DomDistillerStore( | 28 DomDistillerStore::DomDistillerStore( |
28 scoped_ptr<ProtoDatabase<ArticleEntry> > database, | 29 scoped_ptr<ProtoDatabase<ArticleEntry> > database, |
29 const base::FilePath& database_dir) | 30 const base::FilePath& database_dir) |
30 : database_(database.Pass()), | 31 : database_(database.Pass()), |
31 database_loaded_(false), | 32 database_loaded_(false), |
33 attachment_store_(syncer::AttachmentStore::CreateInMemoryStore()), | |
maniscalco
2014/11/12 18:59:44
Is the async construction requirement of the on di
cjhopman
2014/11/14 02:45:15
yes.
| |
32 weak_ptr_factory_(this) { | 34 weak_ptr_factory_(this) { |
33 database_->Init(database_dir, base::Bind(&DomDistillerStore::OnDatabaseInit, | 35 database_->Init(database_dir, base::Bind(&DomDistillerStore::OnDatabaseInit, |
34 weak_ptr_factory_.GetWeakPtr())); | 36 weak_ptr_factory_.GetWeakPtr())); |
35 } | 37 } |
36 | 38 |
37 DomDistillerStore::DomDistillerStore( | 39 DomDistillerStore::DomDistillerStore( |
38 scoped_ptr<ProtoDatabase<ArticleEntry> > database, | 40 scoped_ptr<ProtoDatabase<ArticleEntry> > database, |
39 const std::vector<ArticleEntry>& initial_data, | 41 const std::vector<ArticleEntry>& initial_data, |
40 const base::FilePath& database_dir) | 42 const base::FilePath& database_dir) |
41 : database_(database.Pass()), | 43 : database_(database.Pass()), |
42 database_loaded_(false), | 44 database_loaded_(false), |
45 attachment_store_(syncer::AttachmentStore::CreateInMemoryStore()), | |
43 model_(initial_data), | 46 model_(initial_data), |
44 weak_ptr_factory_(this) { | 47 weak_ptr_factory_(this) { |
45 database_->Init(database_dir, base::Bind(&DomDistillerStore::OnDatabaseInit, | 48 database_->Init(database_dir, base::Bind(&DomDistillerStore::OnDatabaseInit, |
46 weak_ptr_factory_.GetWeakPtr())); | 49 weak_ptr_factory_.GetWeakPtr())); |
47 } | 50 } |
48 | 51 |
49 DomDistillerStore::~DomDistillerStore() {} | 52 DomDistillerStore::~DomDistillerStore() {} |
50 | 53 |
51 // DomDistillerStoreInterface implementation. | 54 // DomDistillerStoreInterface implementation. |
52 syncer::SyncableService* DomDistillerStore::GetSyncableService() { | 55 syncer::SyncableService* DomDistillerStore::GetSyncableService() { |
53 return this; | 56 return this; |
54 } | 57 } |
55 | 58 |
56 bool DomDistillerStore::GetEntryById(const std::string& entry_id, | 59 bool DomDistillerStore::GetEntryById(const std::string& entry_id, |
57 ArticleEntry* entry) { | 60 ArticleEntry* entry) { |
58 return model_.GetEntryById(entry_id, entry); | 61 return model_.GetEntryById(entry_id, entry); |
59 } | 62 } |
60 | 63 |
61 bool DomDistillerStore::GetEntryByUrl(const GURL& url, ArticleEntry* entry) { | 64 bool DomDistillerStore::GetEntryByUrl(const GURL& url, ArticleEntry* entry) { |
62 return model_.GetEntryByUrl(url, entry); | 65 return model_.GetEntryByUrl(url, entry); |
63 } | 66 } |
64 | 67 |
68 void DomDistillerStore::UpdateAttachments( | |
69 const std::string& entry_id, | |
70 scoped_ptr<ArticleAttachmentsData> attachments_data, | |
71 UpdateAttachmentsCallback callback) { | |
maniscalco
2014/11/12 18:59:44
Can be passed by const&.
cjhopman
2014/11/14 02:45:15
Done.
| |
72 if (!GetEntryById(entry_id, nullptr)) { | |
73 base::MessageLoop::current()->PostTask(FROM_HERE, | |
74 base::Bind(callback, false)); | |
75 } | |
76 | |
77 scoped_ptr<sync_pb::ArticleAttachments> article_attachments( | |
78 new sync_pb::ArticleAttachments()); | |
79 syncer::AttachmentList attachment_list; | |
80 attachments_data->CreateSyncAttachments(&attachment_list, | |
81 article_attachments.get()); | |
82 | |
83 attachment_store_->Write( | |
84 attachment_list, | |
85 base::Bind(&DomDistillerStore::OnAttachmentsWrite, | |
86 weak_ptr_factory_.GetWeakPtr(), entry_id, | |
87 base::Passed(&article_attachments), callback)); | |
88 } | |
89 | |
90 void DomDistillerStore::OnAttachmentsWrite( | |
91 const std::string& entry_id, | |
92 scoped_ptr<sync_pb::ArticleAttachments> article_attachments, | |
93 UpdateAttachmentsCallback callback, | |
maniscalco
2014/11/12 18:59:43
Can be passed by const&.
cjhopman
2014/11/14 02:45:15
Done.
| |
94 const syncer::AttachmentStore::Result& result) { | |
95 bool success = result == syncer::AttachmentStore::SUCCESS; | |
maniscalco
2014/11/12 18:59:43
WDYT about using a switch statement without a defa
cjhopman
2014/11/14 02:45:15
Done.
| |
96 if (success) { | |
maniscalco
2014/11/12 18:59:43
I'm thinking about cases where the write might fai
cjhopman
2014/11/14 02:45:15
Yeah, I could see us handling disk full differentl
| |
97 ArticleEntry entry; | |
98 bool has_entry = GetEntryById(entry_id, &entry); | |
99 if (!has_entry) { | |
100 success = false; | |
101 attachment_store_->Drop(GetAttachmentIds(*article_attachments), | |
102 syncer::AttachmentStore::DropCallback()); | |
103 } else { | |
104 if (entry.has_attachments()) { | |
105 attachment_store_->Drop(GetAttachmentIds(entry.attachments()), | |
106 syncer::AttachmentStore::DropCallback()); | |
107 } | |
108 entry.set_allocated_attachments(article_attachments.release()); | |
109 | |
110 SyncChangeList changes_to_apply; | |
111 changes_to_apply.push_back(SyncChange( | |
112 FROM_HERE, SyncChange::ACTION_UPDATE, CreateLocalData(entry))); | |
113 | |
114 SyncChangeList changes_applied; | |
115 SyncChangeList changes_missing; | |
116 | |
117 ApplyChangesToModel(changes_to_apply, &changes_applied, &changes_missing); | |
118 | |
119 DCHECK_EQ(size_t(0), changes_missing.size()); | |
120 DCHECK_EQ(size_t(1), changes_applied.size()); | |
121 | |
122 ApplyChangesToSync(FROM_HERE, changes_applied); | |
123 ApplyChangesToDatabase(changes_applied); | |
124 } | |
125 } | |
126 callback.Run(success); | |
maniscalco
2014/11/12 18:59:44
Is it important that callback executes before cont
cjhopman
2014/11/14 02:45:15
Done.
| |
127 } | |
128 | |
129 void DomDistillerStore::GetAttachments( | |
130 const std::string& entry_id, | |
131 GetAttachmentsCallback callback) { | |
maniscalco
2014/11/12 18:59:44
Can be passed by const&.
cjhopman
2014/11/14 02:45:15
Done.
| |
132 ArticleEntry entry; | |
133 if (!model_.GetEntryById(entry_id, &entry) | |
134 || !entry.has_attachments()) { | |
135 base::MessageLoop::current()->PostTask( | |
136 FROM_HERE, base::Bind(callback, false, nullptr)); | |
137 return; | |
138 } | |
139 | |
140 // TODO(cjhopman): This should use GetOrDownloadAttachments() once there is a | |
141 // feasible way to use that. | |
142 attachment_store_->Read(GetAttachmentIds(entry.attachments()), | |
143 base::Bind(&DomDistillerStore::OnAttachmentsRead, | |
144 weak_ptr_factory_.GetWeakPtr(), | |
145 entry.attachments(), callback)); | |
146 } | |
147 | |
148 void DomDistillerStore::OnAttachmentsRead( | |
149 const sync_pb::ArticleAttachments& attachments_proto, | |
150 GetAttachmentsCallback callback, | |
maniscalco
2014/11/12 18:59:43
Can be passed by const&.
cjhopman
2014/11/14 02:45:15
Done.
| |
151 const syncer::AttachmentStore::Result& result, | |
152 scoped_ptr<syncer::AttachmentMap> attachments, | |
153 scoped_ptr<syncer::AttachmentIdList> missing) { | |
154 bool success = | |
155 (result == syncer::AttachmentStore::SUCCESS) && missing->empty(); | |
156 scoped_ptr<ArticleAttachmentsData> attachments_data; | |
157 if (success) { | |
158 attachments_data = ArticleAttachmentsData::GetFromAttachmentMap( | |
159 attachments_proto, *attachments); | |
160 } | |
161 callback.Run(success, attachments_data.Pass()); | |
162 } | |
163 | |
65 bool DomDistillerStore::AddEntry(const ArticleEntry& entry) { | 164 bool DomDistillerStore::AddEntry(const ArticleEntry& entry) { |
66 return ChangeEntry(entry, SyncChange::ACTION_ADD); | 165 return ChangeEntry(entry, SyncChange::ACTION_ADD); |
67 } | 166 } |
68 | 167 |
69 bool DomDistillerStore::UpdateEntry(const ArticleEntry& entry) { | 168 bool DomDistillerStore::UpdateEntry(const ArticleEntry& entry) { |
70 return ChangeEntry(entry, SyncChange::ACTION_UPDATE); | 169 return ChangeEntry(entry, SyncChange::ACTION_UPDATE); |
71 } | 170 } |
72 | 171 |
73 bool DomDistillerStore::RemoveEntry(const ArticleEntry& entry) { | 172 bool DomDistillerStore::RemoveEntry(const ArticleEntry& entry) { |
74 return ChangeEntry(entry, SyncChange::ACTION_DELETE); | 173 return ChangeEntry(entry, SyncChange::ACTION_DELETE); |
75 } | 174 } |
76 | 175 |
77 bool DomDistillerStore::ChangeEntry(const ArticleEntry& entry, | 176 bool DomDistillerStore::ChangeEntry(const ArticleEntry& entry, |
78 SyncChange::SyncChangeType changeType) { | 177 SyncChange::SyncChangeType changeType) { |
79 if (!database_loaded_) { | 178 if (!database_loaded_) { |
80 return false; | 179 return false; |
81 } | 180 } |
82 | 181 |
83 bool hasEntry = model_.GetEntryById(entry.entry_id(), NULL); | 182 bool hasEntry = model_.GetEntryById(entry.entry_id(), NULL); |
84 if (hasEntry) { | 183 if (hasEntry) { |
85 if (changeType == SyncChange::ACTION_ADD) { | 184 if (changeType == SyncChange::ACTION_ADD) { |
86 DVLOG(1) << "Already have entry with id " << entry.entry_id() << "."; | 185 DVLOG(1) << "Already have entry with id " << entry.entry_id() << "."; |
87 return false; | 186 return false; |
88 } | 187 } |
188 #ifndef NDEBUG | |
maniscalco
2014/11/12 18:59:44
WDYT about moving this code into function and call
cjhopman
2014/11/14 02:45:15
I think it's a great idea.
| |
189 ArticleEntry currentEntry; | |
190 model_.GetEntryById(entry.entry_id(), ¤tEntry); | |
191 DCHECK_EQ(currentEntry.has_attachments(), entry.has_attachments()); | |
192 if (currentEntry.has_attachments()) { | |
193 DCHECK_EQ(currentEntry.attachments().SerializeAsString(), | |
194 entry.attachments().SerializeAsString()); | |
195 } | |
196 #endif | |
89 } else if (changeType != SyncChange::ACTION_ADD) { | 197 } else if (changeType != SyncChange::ACTION_ADD) { |
90 DVLOG(1) << "No entry with id " << entry.entry_id() << " found."; | 198 DVLOG(1) << "No entry with id " << entry.entry_id() << " found."; |
91 return false; | 199 return false; |
92 } | 200 } |
93 | 201 |
94 SyncChangeList changes_to_apply; | 202 SyncChangeList changes_to_apply; |
95 changes_to_apply.push_back( | 203 changes_to_apply.push_back( |
96 SyncChange(FROM_HERE, changeType, CreateLocalData(entry))); | 204 SyncChange(FROM_HERE, changeType, CreateLocalData(entry))); |
97 | 205 |
98 SyncChangeList changes_applied; | 206 SyncChangeList changes_applied; |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
333 result.set_num_items_deleted(0); | 441 result.set_num_items_deleted(0); |
334 | 442 |
335 result.set_pre_association_version(0); | 443 result.set_pre_association_version(0); |
336 result.set_num_items_after_association(model_.GetNumEntries()); | 444 result.set_num_items_after_association(model_.GetNumEntries()); |
337 result.set_error(error); | 445 result.set_error(error); |
338 | 446 |
339 return result; | 447 return result; |
340 } | 448 } |
341 | 449 |
342 } // namespace dom_distiller | 450 } // namespace dom_distiller |
OLD | NEW |