Index: sync/api/attachments/attachment_service_impl.cc |
diff --git a/sync/api/attachments/attachment_service_impl.cc b/sync/api/attachments/attachment_service_impl.cc |
index af2dea7ccc60fa3d7955d21281e456760da7f11d..0570fd407f58588dce43197df5d92979fd0f55de 100644 |
--- a/sync/api/attachments/attachment_service_impl.cc |
+++ b/sync/api/attachments/attachment_service_impl.cc |
@@ -7,17 +7,104 @@ |
#include "base/bind.h" |
#include "base/message_loop/message_loop.h" |
#include "sync/api/attachments/attachment.h" |
+#include "sync/internal_api/public/attachments/fake_attachment_downloader.h" |
#include "sync/internal_api/public/attachments/fake_attachment_store.h" |
#include "sync/internal_api/public/attachments/fake_attachment_uploader.h" |
namespace syncer { |
+// GetOrDownloadAttachments starts multiple parallel DownloadAttachment calls. |
+// GetOrDownloadState tracks completion of these calls and posts callback for |
+// consumer once all attachments are either retrieved or reported unavailable. |
+class AttachmentServiceImpl::GetOrDownloadState |
+ : public base::RefCounted<GetOrDownloadState>, |
+ public base::NonThreadSafe { |
+ public: |
+ GetOrDownloadState(const AttachmentIdList& attachment_ids, |
maniscalco
2014/05/29 22:35:54
Can you document the parameters?
pavely
2014/05/30 00:50:07
Done.
|
+ const GetOrDownloadCallback& callback); |
+ virtual ~GetOrDownloadState(); |
maniscalco
2014/05/29 22:35:54
Probably should make the dtor private. Hmm, I tho
pavely
2014/05/30 00:50:07
Done.
|
+ |
+ // Attachment was just retrieved. Add it to retrieved attachments. |
+ void AddAttachment(Attachment attachment); |
maniscalco
2014/05/29 22:35:54
attachment can be made const ref: const Attachment
pavely
2014/05/30 00:50:07
Done.
|
+ |
+ // Both reading from local store and downloading attachment failed. |
+ // Add it to unavailable set. |
+ void AddUnavailableAttachmentId(const AttachmentId& attachment_id); |
+ |
+ private: |
+ // Request regarding attachment id completed. There is going to be no more |
+ // calls about this attachment. If all attachment requests completed then post |
+ // callback to consumer with results. |
+ void AttachmentRequestCompleted(const AttachmentId& attachment_id); |
+ |
+ GetOrDownloadCallback callback_; |
+ |
+ // Requests for these attachments are still in porgress. |
maniscalco
2014/05/29 22:35:54
s/porgress/progress/
pavely
2014/05/30 00:50:07
Done.
|
+ AttachmentIdSet incomplete_attachments_; |
maniscalco
2014/05/29 22:35:54
Consider renaming to in_progress_attachments_ for
pavely
2014/05/30 00:50:07
in_progress_attachments_ is better.
I first rename
|
+ |
+ AttachmentIdSet unavailable_attachments_; |
+ scoped_ptr<AttachmentMap> retrieved_attachments_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(GetOrDownloadState); |
+}; |
+ |
+AttachmentServiceImpl::GetOrDownloadState::GetOrDownloadState( |
+ const AttachmentIdList& attachment_ids, |
+ const GetOrDownloadCallback& callback) |
+ : callback_(callback), retrieved_attachments_(new AttachmentMap()) { |
+ std::copy( |
+ attachment_ids.begin(), |
+ attachment_ids.end(), |
+ std::inserter(incomplete_attachments_, incomplete_attachments_.end())); |
maniscalco
2014/05/29 22:35:54
Should this be std::back_inserter instead? I can'
pavely
2014/05/30 00:50:07
back_inserter needs push_back(). inserter needs in
maniscalco
2014/05/30 16:08:14
SGTM, std::inserter seems like the way to go.
On
|
+} |
+ |
+AttachmentServiceImpl::GetOrDownloadState::~GetOrDownloadState() { |
+ DCHECK(CalledOnValidThread()); |
+} |
+ |
+void AttachmentServiceImpl::GetOrDownloadState::AddAttachment( |
+ Attachment attachment) { |
+ DCHECK(CalledOnValidThread()); |
+ DCHECK(retrieved_attachments_->find(attachment.GetId()) == |
maniscalco
2014/05/29 22:35:54
FYI, there is a DCHECK_EQ macro. It may or may no
pavely
2014/05/30 00:50:07
The reason for DCHECK_EQ macro is that it will als
|
+ retrieved_attachments_->end()); |
+ retrieved_attachments_->insert( |
+ std::make_pair(attachment.GetId(), attachment)); |
+ AttachmentRequestCompleted(attachment.GetId()); |
+} |
+ |
+void AttachmentServiceImpl::GetOrDownloadState::AddUnavailableAttachmentId( |
+ const AttachmentId& attachment_id) { |
+ DCHECK(CalledOnValidThread()); |
+ DCHECK(unavailable_attachments_.find(attachment_id) == |
+ unavailable_attachments_.end()); |
+ unavailable_attachments_.insert(attachment_id); |
+ AttachmentRequestCompleted(attachment_id); |
+} |
+ |
+void AttachmentServiceImpl::GetOrDownloadState::AttachmentRequestCompleted( |
+ const AttachmentId& attachment_id) { |
+ DCHECK(incomplete_attachments_.find(attachment_id) != |
+ incomplete_attachments_.end()); |
+ incomplete_attachments_.erase(attachment_id); |
+ |
+ if (incomplete_attachments_.empty()) { |
+ // All requests completed. Let's notify consumer. |
+ GetOrDownloadResult result = |
+ unavailable_attachments_.empty() ? GET_SUCCESS : GET_UNSPECIFIED_ERROR; |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback_, result, base::Passed(&retrieved_attachments_))); |
+ } |
+} |
+ |
AttachmentServiceImpl::AttachmentServiceImpl( |
scoped_ptr<AttachmentStore> attachment_store, |
scoped_ptr<AttachmentUploader> attachment_uploader, |
+ scoped_ptr<AttachmentDownloader> attachment_downloader, |
Delegate* delegate) |
: attachment_store_(attachment_store.Pass()), |
attachment_uploader_(attachment_uploader.Pass()), |
+ attachment_downloader_(attachment_downloader.Pass()), |
delegate_(delegate), |
weak_ptr_factory_(this) { |
DCHECK(CalledOnValidThread()); |
@@ -35,9 +122,13 @@ scoped_ptr<syncer::AttachmentService> AttachmentServiceImpl::CreateForTest() { |
new syncer::FakeAttachmentStore(base::MessageLoopProxy::current())); |
scoped_ptr<AttachmentUploader> attachment_uploader( |
new FakeAttachmentUploader); |
+ scoped_ptr<AttachmentDownloader> attachment_downloader( |
+ new FakeAttachmentDownloader()); |
scoped_ptr<syncer::AttachmentService> attachment_service( |
- new syncer::AttachmentServiceImpl( |
- attachment_store.Pass(), attachment_uploader.Pass(), NULL)); |
+ new syncer::AttachmentServiceImpl(attachment_store.Pass(), |
+ attachment_uploader.Pass(), |
+ attachment_downloader.Pass(), |
+ NULL)); |
return attachment_service.Pass(); |
} |
@@ -45,10 +136,12 @@ void AttachmentServiceImpl::GetOrDownloadAttachments( |
const AttachmentIdList& attachment_ids, |
const GetOrDownloadCallback& callback) { |
DCHECK(CalledOnValidThread()); |
+ scoped_refptr<GetOrDownloadState> state( |
+ new GetOrDownloadState(attachment_ids, callback)); |
attachment_store_->Read(attachment_ids, |
base::Bind(&AttachmentServiceImpl::ReadDone, |
weak_ptr_factory_.GetWeakPtr(), |
- callback)); |
+ state)); |
} |
void AttachmentServiceImpl::DropAttachments( |
@@ -96,18 +189,29 @@ void AttachmentServiceImpl::OnSyncDataUpdate( |
} |
void AttachmentServiceImpl::ReadDone( |
- const GetOrDownloadCallback& callback, |
+ const scoped_refptr<GetOrDownloadState>& state, |
const AttachmentStore::Result& result, |
scoped_ptr<AttachmentMap> attachments, |
scoped_ptr<AttachmentIdList> unavailable_attachment_ids) { |
- AttachmentService::GetOrDownloadResult get_result = |
- AttachmentService::GET_UNSPECIFIED_ERROR; |
- if (result == AttachmentStore::SUCCESS) { |
- get_result = AttachmentService::GET_SUCCESS; |
+ // Add read attachments to result. |
+ for (AttachmentMap::const_iterator iter = attachments->begin(); |
+ iter != attachments->end(); |
+ ++iter) { |
+ state->AddAttachment(iter->second); |
+ } |
+ // Try to download locally unavailable attachments. |
+ for (AttachmentIdList::const_iterator iter = |
+ unavailable_attachment_ids->begin(); |
+ iter != unavailable_attachment_ids->end(); |
+ ++iter) { |
+ attachment_downloader_->DownloadAttachment( |
+ *iter, |
+ base::Bind(&AttachmentServiceImpl::DownloadDone, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ state, |
+ *iter)); |
+ ; |
} |
- // TODO(maniscalco): Deal with case where an error occurred (bug 361251). |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, base::Bind(callback, get_result, base::Passed(&attachments))); |
} |
void AttachmentServiceImpl::DropDone(const DropCallback& callback, |
@@ -145,4 +249,16 @@ void AttachmentServiceImpl::UploadDone( |
} |
} |
+void AttachmentServiceImpl::DownloadDone( |
+ const scoped_refptr<GetOrDownloadState>& state, |
+ const AttachmentId& attachment_id, |
+ const AttachmentDownloader::DownloadResult& result, |
+ scoped_ptr<Attachment> attachment) { |
+ if (result == AttachmentDownloader::DOWNLOAD_SUCCESS) { |
+ state->AddAttachment(*attachment.get()); |
+ } else { |
+ state->AddUnavailableAttachmentId(attachment_id); |
+ } |
+} |
+ |
} // namespace syncer |