| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "peridot/bin/ledger/app/sync_watcher_set.h" |
| |
| #include <lib/fit/function.h> |
| |
| namespace ledger { |
| namespace { |
| SyncState ConvertToSyncState(sync_coordinator::DownloadSyncState download) { |
| switch (download) { |
| case sync_coordinator::DOWNLOAD_IDLE: |
| return SyncState::IDLE; |
| case sync_coordinator::DOWNLOAD_PENDING: |
| return SyncState::PENDING; |
| case sync_coordinator::DOWNLOAD_IN_PROGRESS: |
| return SyncState::IN_PROGRESS; |
| case sync_coordinator::DOWNLOAD_ERROR: |
| return SyncState::ERROR; |
| } |
| } |
| |
| SyncState ConvertToSyncState(sync_coordinator::UploadSyncState upload) { |
| switch (upload) { |
| case sync_coordinator::UPLOAD_IDLE: |
| return SyncState::IDLE; |
| case sync_coordinator::UPLOAD_PENDING: |
| return SyncState::PENDING; |
| case sync_coordinator::UPLOAD_IN_PROGRESS: |
| return SyncState::IN_PROGRESS; |
| case sync_coordinator::UPLOAD_ERROR: |
| return SyncState::ERROR; |
| } |
| } |
| |
| bool operator==( |
| const sync_coordinator::SyncStateWatcher::SyncStateContainer& lhs, |
| const sync_coordinator::SyncStateWatcher::SyncStateContainer& rhs) { |
| return std::tie(lhs.download, lhs.upload) == |
| std::tie(rhs.download, rhs.upload); |
| } |
| } // namespace |
| |
| class SyncWatcherSet::SyncWatcherContainer |
| : public sync_coordinator::SyncStateWatcher { |
| public: |
| explicit SyncWatcherContainer(SyncWatcherPtr watcher) |
| : watcher_(std::move(watcher)) {} |
| |
| ~SyncWatcherContainer() override {} |
| |
| void Start(SyncStateContainer base_state) { |
| pending_ = base_state; |
| Send(); |
| } |
| |
| void Notify(SyncStateContainer sync_state) override { |
| if (sync_state == pending_) { |
| return; |
| } |
| pending_ = sync_state; |
| |
| SendIfPending(); |
| } |
| |
| void set_on_empty(fit::closure on_empty_callback) { |
| if (on_empty_callback) { |
| watcher_.set_error_handler([callback = std::move(on_empty_callback)]( |
| zx_status_t status) { callback(); }); |
| } |
| } |
| |
| private: |
| void SendIfPending() { |
| if (!watcher_ || notification_in_progress_ || last_ == pending_) { |
| return; |
| } |
| Send(); |
| } |
| |
| void Send() { |
| notification_in_progress_ = true; |
| last_ = pending_; |
| watcher_->SyncStateChanged(ConvertToSyncState(last_.download), |
| ConvertToSyncState(last_.upload), [this]() { |
| notification_in_progress_ = false; |
| SendIfPending(); |
| }); |
| } |
| |
| // fidl interface to the client. |
| SyncWatcherPtr watcher_; |
| |
| // True if a notification has been sent but not acknowledged by the client. |
| bool notification_in_progress_ = false; |
| // pending_ contains the next synchronization state to send to the watcher, |
| // or the current one if no notification is currently in progress |
| SyncStateContainer pending_; |
| // last_ contains the last sent notification. |
| SyncStateContainer last_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(SyncWatcherContainer); |
| }; |
| |
| SyncWatcherSet::SyncWatcherSet() {} |
| |
| SyncWatcherSet::~SyncWatcherSet() {} |
| |
| void SyncWatcherSet::AddSyncWatcher( |
| fidl::InterfaceHandle<SyncWatcher> watcher) { |
| SyncWatcherContainer& container = watchers_.emplace(watcher.Bind()); |
| container.Start(current_); |
| } |
| |
| void SyncWatcherSet::Notify(SyncStateContainer sync_state) { |
| if (current_ == sync_state) { |
| // Skip notifying if nothing has changed. |
| return; |
| } |
| current_ = sync_state; |
| for (SyncWatcherContainer& watcher : watchers_) { |
| watcher.Notify(current_); |
| } |
| } |
| |
| } // namespace ledger |