OLD | NEW |
| (Empty) |
1 // Copyright 2014 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. | |
4 | |
5 #include "sync/api/attachments/attachment_service_impl.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "base/thread_task_runner_handle.h" | |
10 #include "sync/api/attachments/attachment.h" | |
11 #include "sync/internal_api/public/attachments/fake_attachment_downloader.h" | |
12 #include "sync/internal_api/public/attachments/fake_attachment_store.h" | |
13 #include "sync/internal_api/public/attachments/fake_attachment_uploader.h" | |
14 | |
15 namespace syncer { | |
16 | |
17 // GetOrDownloadAttachments starts multiple parallel DownloadAttachment calls. | |
18 // GetOrDownloadState tracks completion of these calls and posts callback for | |
19 // consumer once all attachments are either retrieved or reported unavailable. | |
20 class AttachmentServiceImpl::GetOrDownloadState | |
21 : public base::RefCounted<GetOrDownloadState>, | |
22 public base::NonThreadSafe { | |
23 public: | |
24 // GetOrDownloadState gets parameter from values passed to | |
25 // AttachmentService::GetOrDownloadAttachments. | |
26 // |attachment_ids| is a list of attachmens to retrieve. | |
27 // |callback| will be posted on current thread when all attachments retrieved | |
28 // or confirmed unavailable. | |
29 GetOrDownloadState(const AttachmentIdList& attachment_ids, | |
30 const GetOrDownloadCallback& callback); | |
31 | |
32 // Attachment was just retrieved. Add it to retrieved attachments. | |
33 void AddAttachment(const Attachment& attachment); | |
34 | |
35 // Both reading from local store and downloading attachment failed. | |
36 // Add it to unavailable set. | |
37 void AddUnavailableAttachmentId(const AttachmentId& attachment_id); | |
38 | |
39 private: | |
40 friend class base::RefCounted<GetOrDownloadState>; | |
41 virtual ~GetOrDownloadState(); | |
42 | |
43 // If all attachment requests completed then post callback to consumer with | |
44 // results. | |
45 void PostResultIfAllRequestsCompleted(); | |
46 | |
47 GetOrDownloadCallback callback_; | |
48 | |
49 // Requests for these attachments are still in progress. | |
50 AttachmentIdSet in_progress_attachments_; | |
51 | |
52 AttachmentIdSet unavailable_attachments_; | |
53 scoped_ptr<AttachmentMap> retrieved_attachments_; | |
54 | |
55 DISALLOW_COPY_AND_ASSIGN(GetOrDownloadState); | |
56 }; | |
57 | |
58 AttachmentServiceImpl::GetOrDownloadState::GetOrDownloadState( | |
59 const AttachmentIdList& attachment_ids, | |
60 const GetOrDownloadCallback& callback) | |
61 : callback_(callback), retrieved_attachments_(new AttachmentMap()) { | |
62 std::copy( | |
63 attachment_ids.begin(), | |
64 attachment_ids.end(), | |
65 std::inserter(in_progress_attachments_, in_progress_attachments_.end())); | |
66 PostResultIfAllRequestsCompleted(); | |
67 } | |
68 | |
69 AttachmentServiceImpl::GetOrDownloadState::~GetOrDownloadState() { | |
70 DCHECK(CalledOnValidThread()); | |
71 } | |
72 | |
73 void AttachmentServiceImpl::GetOrDownloadState::AddAttachment( | |
74 const Attachment& attachment) { | |
75 DCHECK(CalledOnValidThread()); | |
76 DCHECK(retrieved_attachments_->find(attachment.GetId()) == | |
77 retrieved_attachments_->end()); | |
78 retrieved_attachments_->insert( | |
79 std::make_pair(attachment.GetId(), attachment)); | |
80 DCHECK(in_progress_attachments_.find(attachment.GetId()) != | |
81 in_progress_attachments_.end()); | |
82 in_progress_attachments_.erase(attachment.GetId()); | |
83 PostResultIfAllRequestsCompleted(); | |
84 } | |
85 | |
86 void AttachmentServiceImpl::GetOrDownloadState::AddUnavailableAttachmentId( | |
87 const AttachmentId& attachment_id) { | |
88 DCHECK(CalledOnValidThread()); | |
89 DCHECK(unavailable_attachments_.find(attachment_id) == | |
90 unavailable_attachments_.end()); | |
91 unavailable_attachments_.insert(attachment_id); | |
92 DCHECK(in_progress_attachments_.find(attachment_id) != | |
93 in_progress_attachments_.end()); | |
94 in_progress_attachments_.erase(attachment_id); | |
95 PostResultIfAllRequestsCompleted(); | |
96 } | |
97 | |
98 void | |
99 AttachmentServiceImpl::GetOrDownloadState::PostResultIfAllRequestsCompleted() { | |
100 if (in_progress_attachments_.empty()) { | |
101 // All requests completed. Let's notify consumer. | |
102 GetOrDownloadResult result = | |
103 unavailable_attachments_.empty() ? GET_SUCCESS : GET_UNSPECIFIED_ERROR; | |
104 base::MessageLoop::current()->PostTask( | |
105 FROM_HERE, | |
106 base::Bind(callback_, result, base::Passed(&retrieved_attachments_))); | |
107 } | |
108 } | |
109 | |
110 AttachmentServiceImpl::AttachmentServiceImpl( | |
111 scoped_ptr<AttachmentStore> attachment_store, | |
112 scoped_ptr<AttachmentUploader> attachment_uploader, | |
113 scoped_ptr<AttachmentDownloader> attachment_downloader, | |
114 Delegate* delegate) | |
115 : attachment_store_(attachment_store.Pass()), | |
116 attachment_uploader_(attachment_uploader.Pass()), | |
117 attachment_downloader_(attachment_downloader.Pass()), | |
118 delegate_(delegate), | |
119 weak_ptr_factory_(this) { | |
120 DCHECK(CalledOnValidThread()); | |
121 DCHECK(attachment_store_); | |
122 } | |
123 | |
124 AttachmentServiceImpl::~AttachmentServiceImpl() { | |
125 DCHECK(CalledOnValidThread()); | |
126 } | |
127 | |
128 // Static. | |
129 scoped_ptr<syncer::AttachmentService> AttachmentServiceImpl::CreateForTest() { | |
130 scoped_ptr<syncer::AttachmentStore> attachment_store( | |
131 new syncer::FakeAttachmentStore(base::ThreadTaskRunnerHandle::Get())); | |
132 scoped_ptr<AttachmentUploader> attachment_uploader( | |
133 new FakeAttachmentUploader); | |
134 scoped_ptr<AttachmentDownloader> attachment_downloader( | |
135 new FakeAttachmentDownloader()); | |
136 scoped_ptr<syncer::AttachmentService> attachment_service( | |
137 new syncer::AttachmentServiceImpl(attachment_store.Pass(), | |
138 attachment_uploader.Pass(), | |
139 attachment_downloader.Pass(), | |
140 NULL)); | |
141 return attachment_service.Pass(); | |
142 } | |
143 | |
144 void AttachmentServiceImpl::GetOrDownloadAttachments( | |
145 const AttachmentIdList& attachment_ids, | |
146 const GetOrDownloadCallback& callback) { | |
147 DCHECK(CalledOnValidThread()); | |
148 scoped_refptr<GetOrDownloadState> state( | |
149 new GetOrDownloadState(attachment_ids, callback)); | |
150 attachment_store_->Read(attachment_ids, | |
151 base::Bind(&AttachmentServiceImpl::ReadDone, | |
152 weak_ptr_factory_.GetWeakPtr(), | |
153 state)); | |
154 } | |
155 | |
156 void AttachmentServiceImpl::DropAttachments( | |
157 const AttachmentIdList& attachment_ids, | |
158 const DropCallback& callback) { | |
159 DCHECK(CalledOnValidThread()); | |
160 attachment_store_->Drop(attachment_ids, | |
161 base::Bind(&AttachmentServiceImpl::DropDone, | |
162 weak_ptr_factory_.GetWeakPtr(), | |
163 callback)); | |
164 } | |
165 | |
166 void AttachmentServiceImpl::StoreAttachments(const AttachmentList& attachments, | |
167 const StoreCallback& callback) { | |
168 DCHECK(CalledOnValidThread()); | |
169 attachment_store_->Write(attachments, | |
170 base::Bind(&AttachmentServiceImpl::WriteDone, | |
171 weak_ptr_factory_.GetWeakPtr(), | |
172 callback)); | |
173 if (attachment_uploader_.get()) { | |
174 for (AttachmentList::const_iterator iter = attachments.begin(); | |
175 iter != attachments.end(); | |
176 ++iter) { | |
177 attachment_uploader_->UploadAttachment( | |
178 *iter, | |
179 base::Bind(&AttachmentServiceImpl::UploadDone, | |
180 weak_ptr_factory_.GetWeakPtr())); | |
181 } | |
182 } | |
183 } | |
184 | |
185 void AttachmentServiceImpl::ReadDone( | |
186 const scoped_refptr<GetOrDownloadState>& state, | |
187 const AttachmentStore::Result& result, | |
188 scoped_ptr<AttachmentMap> attachments, | |
189 scoped_ptr<AttachmentIdList> unavailable_attachment_ids) { | |
190 // Add read attachments to result. | |
191 for (AttachmentMap::const_iterator iter = attachments->begin(); | |
192 iter != attachments->end(); | |
193 ++iter) { | |
194 state->AddAttachment(iter->second); | |
195 } | |
196 | |
197 AttachmentIdList::const_iterator iter = unavailable_attachment_ids->begin(); | |
198 AttachmentIdList::const_iterator end = unavailable_attachment_ids->end(); | |
199 if (attachment_downloader_.get()) { | |
200 // Try to download locally unavailable attachments. | |
201 for (; iter != end; ++iter) { | |
202 attachment_downloader_->DownloadAttachment( | |
203 *iter, | |
204 base::Bind(&AttachmentServiceImpl::DownloadDone, | |
205 weak_ptr_factory_.GetWeakPtr(), | |
206 state, | |
207 *iter)); | |
208 } | |
209 } else { | |
210 // No downloader so all locally unavailable attachments are unavailable. | |
211 for (; iter != end; ++iter) { | |
212 state->AddUnavailableAttachmentId(*iter); | |
213 } | |
214 } | |
215 } | |
216 | |
217 void AttachmentServiceImpl::DropDone(const DropCallback& callback, | |
218 const AttachmentStore::Result& result) { | |
219 AttachmentService::DropResult drop_result = | |
220 AttachmentService::DROP_UNSPECIFIED_ERROR; | |
221 if (result == AttachmentStore::SUCCESS) { | |
222 drop_result = AttachmentService::DROP_SUCCESS; | |
223 } | |
224 // TODO(maniscalco): Deal with case where an error occurred (bug 361251). | |
225 base::MessageLoop::current()->PostTask(FROM_HERE, | |
226 base::Bind(callback, drop_result)); | |
227 } | |
228 | |
229 void AttachmentServiceImpl::WriteDone(const StoreCallback& callback, | |
230 const AttachmentStore::Result& result) { | |
231 AttachmentService::StoreResult store_result = | |
232 AttachmentService::STORE_UNSPECIFIED_ERROR; | |
233 if (result == AttachmentStore::SUCCESS) { | |
234 store_result = AttachmentService::STORE_SUCCESS; | |
235 } | |
236 // TODO(maniscalco): Deal with case where an error occurred (bug 361251). | |
237 base::MessageLoop::current()->PostTask(FROM_HERE, | |
238 base::Bind(callback, store_result)); | |
239 } | |
240 | |
241 void AttachmentServiceImpl::UploadDone( | |
242 const AttachmentUploader::UploadResult& result, | |
243 const AttachmentId& attachment_id) { | |
244 // TODO(pavely): crbug/372622: Deal with UploadAttachment failures. | |
245 if (result != AttachmentUploader::UPLOAD_SUCCESS) | |
246 return; | |
247 if (delegate_) { | |
248 delegate_->OnAttachmentUploaded(attachment_id); | |
249 } | |
250 } | |
251 | |
252 void AttachmentServiceImpl::DownloadDone( | |
253 const scoped_refptr<GetOrDownloadState>& state, | |
254 const AttachmentId& attachment_id, | |
255 const AttachmentDownloader::DownloadResult& result, | |
256 scoped_ptr<Attachment> attachment) { | |
257 if (result == AttachmentDownloader::DOWNLOAD_SUCCESS) { | |
258 state->AddAttachment(*attachment.get()); | |
259 } else { | |
260 state->AddUnavailableAttachmentId(attachment_id); | |
261 } | |
262 } | |
263 | |
264 } // namespace syncer | |
OLD | NEW |