| 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..45134952e557db4fd5f02dfabd04f668bcadf7ca 100644
|
| --- a/sync/api/attachments/attachment_service_impl.cc
|
| +++ b/sync/api/attachments/attachment_service_impl.cc
|
| @@ -7,17 +7,113 @@
|
| #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 gets parameter from values passed to
|
| + // AttachmentService::GetOrDownloadAttachments.
|
| + // |attachment_ids| is a list of attachmens to retrieve.
|
| + // |callback| will be posted on current thread when all attachments retrieved
|
| + // or confirmed unavailable.
|
| + GetOrDownloadState(const AttachmentIdList& attachment_ids,
|
| + const GetOrDownloadCallback& callback);
|
| +
|
| + // Attachment was just retrieved. Add it to retrieved attachments.
|
| + void AddAttachment(const Attachment& attachment);
|
| +
|
| + // Both reading from local store and downloading attachment failed.
|
| + // Add it to unavailable set.
|
| + void AddUnavailableAttachmentId(const AttachmentId& attachment_id);
|
| +
|
| + private:
|
| + friend class base::RefCounted<GetOrDownloadState>;
|
| + virtual ~GetOrDownloadState();
|
| +
|
| + // If all attachment requests completed then post callback to consumer with
|
| + // results.
|
| + void PostResultIfAllRequestsCompleted();
|
| +
|
| + GetOrDownloadCallback callback_;
|
| +
|
| + // Requests for these attachments are still in progress.
|
| + AttachmentIdSet in_progress_attachments_;
|
| +
|
| + 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(in_progress_attachments_, in_progress_attachments_.end()));
|
| + PostResultIfAllRequestsCompleted();
|
| +}
|
| +
|
| +AttachmentServiceImpl::GetOrDownloadState::~GetOrDownloadState() {
|
| + DCHECK(CalledOnValidThread());
|
| +}
|
| +
|
| +void AttachmentServiceImpl::GetOrDownloadState::AddAttachment(
|
| + const Attachment& attachment) {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK(retrieved_attachments_->find(attachment.GetId()) ==
|
| + retrieved_attachments_->end());
|
| + retrieved_attachments_->insert(
|
| + std::make_pair(attachment.GetId(), attachment));
|
| + DCHECK(in_progress_attachments_.find(attachment.GetId()) !=
|
| + in_progress_attachments_.end());
|
| + in_progress_attachments_.erase(attachment.GetId());
|
| + PostResultIfAllRequestsCompleted();
|
| +}
|
| +
|
| +void AttachmentServiceImpl::GetOrDownloadState::AddUnavailableAttachmentId(
|
| + const AttachmentId& attachment_id) {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK(unavailable_attachments_.find(attachment_id) ==
|
| + unavailable_attachments_.end());
|
| + unavailable_attachments_.insert(attachment_id);
|
| + DCHECK(in_progress_attachments_.find(attachment_id) !=
|
| + in_progress_attachments_.end());
|
| + in_progress_attachments_.erase(attachment_id);
|
| + PostResultIfAllRequestsCompleted();
|
| +}
|
| +
|
| +void
|
| +AttachmentServiceImpl::GetOrDownloadState::PostResultIfAllRequestsCompleted() {
|
| + if (in_progress_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 +131,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 +145,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 +198,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 +258,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
|
|
|