Chromium Code Reviews| Index: content/browser/background_sync/background_sync_manager.cc |
| diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d5291ce8bdc06468a44a612a7c512e98169e9588 |
| --- /dev/null |
| +++ b/content/browser/background_sync/background_sync_manager.cc |
| @@ -0,0 +1,321 @@ |
| +// Copyright 2015 The Chromium 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 "content/browser/background_sync/background_sync_manager.h" |
| + |
| +#include "base/barrier_closure.h" |
| +#include "base/bind.h" |
| +#include "content/browser/background_sync/background_sync.pb.h" |
| +#include "content/browser/service_worker/service_worker_cache_scheduler.h" |
| +#include "content/browser/service_worker/service_worker_context_wrapper.h" |
| +#include "content/browser/service_worker/service_worker_storage.h" |
| +#include "content/public/browser/browser_thread.h" |
| + |
| +namespace { |
| +const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData"; |
| +} |
| + |
| +namespace content { |
| + |
| +// static |
| +scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create( |
| + const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) { |
| + BackgroundSyncManager* sync_manager = |
| + new BackgroundSyncManager(service_worker_context); |
| + sync_manager->Init(); |
| + return make_scoped_ptr(sync_manager); |
| +} |
| + |
| +BackgroundSyncManager::~BackgroundSyncManager() { |
| +} |
| + |
| +void BackgroundSyncManager::Register( |
| + const GURL& origin, |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration, |
| + const StatusAndRegistrationCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + DCHECK(initialized_ || initializing_); |
| + |
| + StatusAndRegistrationCallback pending_callback = |
| + base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback, |
| + weak_ptr_factory_.GetWeakPtr(), callback); |
| + |
| + op_scheduler_->ScheduleOperation(base::Bind( |
| + &BackgroundSyncManager::RegisterImpl, weak_ptr_factory_.GetWeakPtr(), |
| + origin, sw_registration_id, sync_registration, pending_callback)); |
| +} |
| + |
| +void BackgroundSyncManager::Unregister( |
| + const GURL& origin, |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration, |
| + const StatusCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + DCHECK(initialized_ || initializing_); |
| + |
| + StatusCallback pending_callback = |
| + base::Bind(&BackgroundSyncManager::PendingStatusCallback, |
| + weak_ptr_factory_.GetWeakPtr(), callback); |
| + |
| + op_scheduler_->ScheduleOperation(base::Bind( |
| + &BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(), |
| + origin, sw_registration_id, sync_registration, pending_callback)); |
| +} |
| + |
| +void BackgroundSyncManager::GetRegistration( |
| + const GURL& origin, |
| + int64 sw_registration_id, |
| + const std::string sync_registration_id, |
| + const StatusAndRegistrationCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + DCHECK(initialized_ || initializing_); |
| + |
| + StatusAndRegistrationCallback pending_callback = |
| + base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback, |
| + weak_ptr_factory_.GetWeakPtr(), callback); |
| + |
| + op_scheduler_->ScheduleOperation( |
| + base::Bind(&BackgroundSyncManager::GetRegistrationImpl, |
| + weak_ptr_factory_.GetWeakPtr(), origin, sw_registration_id, |
| + sync_registration_id, pending_callback)); |
| +} |
| + |
| +BackgroundSyncManager::BackgroundSyncManager( |
| + const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) |
| + : initialized_(false), |
| + initializing_(false), |
| + registration_map_(new IdToRegistrationMap()), |
| + op_scheduler_(new ServiceWorkerCacheScheduler()), |
| + service_worker_context_(service_worker_context), |
| + weak_ptr_factory_(this) { |
| +} |
| + |
| +void BackgroundSyncManager::Init() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + DCHECK(!initialized_ && !initializing_); |
| + DCHECK(op_scheduler_->Empty()); |
| + |
| + initializing_ = true; |
| + op_scheduler_->ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BackgroundSyncManager::InitImpl() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + DCHECK(!initialized_); |
| + DCHECK(initializing_); |
| + |
| + service_worker_context_->context()->storage()->GetUserDataForAllRegistrations( |
| + kBackgroundSyncUserDataKey, |
| + base::Bind(&BackgroundSyncManager::InitDidGetUserData, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BackgroundSyncManager::InitDidGetUserData( |
| + const std::vector<std::pair<int64, std::string>>& user_data, |
| + ServiceWorkerStatusCode status) { |
| + for (const std::pair<int64, std::string>& data : user_data) { |
| + BackgroundSyncRegistrationsProto registrations_proto; |
| + if (registrations_proto.ParseFromString(data.second)) { |
| + for (int i = 0, max = registrations_proto.registration_size(); i < max; |
| + ++i) { |
| + const BackgroundSyncRegistrationProto& registration_proto = |
| + registrations_proto.registration(i); |
| + (*registration_map_)[data.first].push_back( |
| + BackgroundSyncRegistration(registration_proto.id())); |
| + } |
| + } |
| + } |
| + |
| + initializing_ = false; |
| + initialized_ = true; |
| + |
| + // TODO(jkarlin): Call the scheduling algorithm here. |
| + |
| + op_scheduler_->CompleteOperationAndRunNext(); |
| +} |
| + |
| +void BackgroundSyncManager::RegisterImpl( |
| + const GURL& origin, |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration, |
| + const StatusAndRegistrationCallback& callback) { |
| + // TODO(jkarlin): Check for permission. |
|
davidben
2015/03/13 22:05:43
(Seems an important thing to do. :-P)
jkarlin
2015/03/14 01:17:27
Yes, though we're protected by (two) command line
|
| + |
| + if (!AddRegistrationToMap(sw_registration_id, sync_registration)) { |
| + callback.Run(ErrorTypeExists, BackgroundSyncRegistration("")); |
|
davidben
2015/03/13 22:05:43
Between this and everyone futher up the stack, it
jkarlin
2015/03/14 01:17:27
RunSoon is a good idea, done.
|
| + return; |
| + } |
| + |
| + StoreRegistrations( |
| + origin, sw_registration_id, |
| + base::Bind(&BackgroundSyncManager::RegisterDidStore, |
| + weak_ptr_factory_.GetWeakPtr(), sw_registration_id, |
| + sync_registration, callback)); |
| +} |
| + |
| +bool BackgroundSyncManager::HasRegistration( |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration) { |
| + IdToRegistrationMap::iterator it = |
| + registration_map_->find(sw_registration_id); |
| + if (it == registration_map_->end()) |
| + return false; |
| + |
| + for (const BackgroundSyncRegistration& reg : it->second) { |
| + if (sync_registration.id == reg.id) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +void BackgroundSyncManager::StoreRegistrations( |
| + const GURL& origin, |
| + int64 sw_registration_id, |
| + const ServiceWorkerStorage::StatusCallback& callback) { |
| + // Serialize the data. |
| + BackgroundSyncRegistrationsProto registrations_proto; |
| + for (const BackgroundSyncRegistration& sync_registration : |
| + (*registration_map_)[sw_registration_id]) { |
| + BackgroundSyncRegistrationProto* registration_proto = |
| + registrations_proto.add_registration(); |
| + registration_proto->set_id(sync_registration.id); |
| + } |
|
davidben
2015/03/13 22:05:43
Writing N registrations takes O(N^2). Is this a pr
jkarlin
2015/03/14 01:17:27
The thought is that the lists will be small. In w
|
| + std::string serialized; |
| + bool success = registrations_proto.SerializeToString(&serialized); |
| + DCHECK(success); |
| + |
| + // Store it. |
| + service_worker_context_->context()->storage()->StoreUserData( |
| + sw_registration_id, origin, kBackgroundSyncUserDataKey, serialized, |
| + callback); |
| +} |
| + |
| +void BackgroundSyncManager::RegisterDidStore( |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration, |
| + const StatusAndRegistrationCallback& callback, |
| + ServiceWorkerStatusCode status) { |
| + if (status != SERVICE_WORKER_OK) { |
| + // Restore the previous state. |
| + RemoveRegistrationFromMap(sw_registration_id, sync_registration); |
| + callback.Run(ErrorTypeStorage, BackgroundSyncRegistration()); |
| + return; |
| + } |
| + // TODO(jkarlin): Run the registration algorithm. |
| + callback.Run(ErrorTypeOK, sync_registration); |
| +} |
| + |
| +bool BackgroundSyncManager::RemoveRegistrationFromMap( |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration) { |
| + IdToRegistrationMap::iterator it = |
| + registration_map_->find(sw_registration_id); |
| + |
| + if (it == registration_map_->end()) |
| + return false; |
| + |
| + std::list<BackgroundSyncRegistration>* registrations = &(it->second); |
| + for (std::list<BackgroundSyncRegistration>::iterator reg_iter = |
| + registrations->begin(); |
| + reg_iter != registrations->end(); ++reg_iter) { |
| + if (reg_iter->id == sync_registration.id) { |
| + registrations->erase(reg_iter); |
| + return true; |
| + } |
| + } |
| + |
| + return false; |
| +} |
| + |
| +bool BackgroundSyncManager::AddRegistrationToMap( |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration) { |
| + if (HasRegistration(sw_registration_id, sync_registration)) |
| + return false; |
| + |
| + (*registration_map_)[sw_registration_id].push_back(sync_registration); |
| + return true; |
| +} |
| + |
| +void BackgroundSyncManager::UnregisterImpl( |
| + const GURL& origin, |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration, |
| + const StatusCallback& callback) { |
| + if (!RemoveRegistrationFromMap(sw_registration_id, sync_registration)) { |
| + callback.Run(ErrorTypeNotFound); |
| + return; |
| + } |
| + |
| + StoreRegistrations( |
| + origin, sw_registration_id, |
| + base::Bind(&BackgroundSyncManager::UnregisterDidStore, |
| + weak_ptr_factory_.GetWeakPtr(), sw_registration_id, |
| + sync_registration, callback)); |
| +} |
| + |
| +void BackgroundSyncManager::UnregisterDidStore( |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration, |
| + const StatusCallback& callback, |
| + ServiceWorkerStatusCode status) { |
| + if (status != SERVICE_WORKER_OK) { |
| + // Restore the previous state. |
| + AddRegistrationToMap(sw_registration_id, sync_registration); |
| + callback.Run(ErrorTypeStorage); |
| + return; |
| + } |
| + |
| + // TODO(jkarlin): Run the registration algorithm. |
| + callback.Run(ErrorTypeOK); |
| +} |
| + |
| +void BackgroundSyncManager::GetRegistrationImpl( |
| + const GURL& origin, |
| + int64 sw_registration_id, |
| + const std::string sync_registration_id, |
| + const StatusAndRegistrationCallback& callback) { |
| + IdToRegistrationMap::iterator it = |
| + registration_map_->find(sw_registration_id); |
| + |
| + if (it == registration_map_->end()) { |
| + callback.Run(ErrorTypeNotFound, BackgroundSyncRegistration()); |
| + return; |
| + } |
| + |
| + std::list<BackgroundSyncRegistration>* registrations = &(it->second); |
| + for (std::list<BackgroundSyncRegistration>::iterator reg_iter = |
| + registrations->begin(); |
| + reg_iter != registrations->end(); ++reg_iter) { |
|
davidben
2015/03/13 22:05:43
for-each loop?
jkarlin
2015/03/14 01:17:27
Done.
|
| + if (reg_iter->id == sync_registration_id) { |
| + callback.Run(ErrorTypeOK, *reg_iter); |
| + return; |
| + } |
| + } |
| + |
| + callback.Run(ErrorTypeNotFound, BackgroundSyncRegistration()); |
| +} |
| + |
| +void BackgroundSyncManager::PendingStatusAndRegistrationCallback( |
| + const StatusAndRegistrationCallback& callback, |
| + ErrorType error, |
| + const BackgroundSyncRegistration& sync_registration) { |
| + base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr(); |
|
davidben
2015/03/13 22:05:43
Worth a comment explaining what's going on here? (
jkarlin
2015/03/14 01:17:27
Added comments. The callback is from outside of th
|
| + callback.Run(error, sync_registration); |
| + if (manager) |
| + op_scheduler_->CompleteOperationAndRunNext(); |
| +} |
| + |
| +void BackgroundSyncManager::PendingStatusCallback( |
| + const StatusCallback& callback, |
| + ErrorType error) { |
| + base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr(); |
| + callback.Run(error); |
| + if (manager) |
| + op_scheduler_->CompleteOperationAndRunNext(); |
| +} |
| + |
| +} // namespace content |