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..715493523a512f2050068e2e7490a0a1bd64183c |
--- /dev/null |
+++ b/content/browser/background_sync/background_sync_manager.cc |
@@ -0,0 +1,394 @@ |
+// 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_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 { |
+ |
+BackgroundSyncManager::BackgroundSyncRegistrations:: |
+ BackgroundSyncRegistrations() |
+ : id_counter(kInitialCounterId) { |
+} |
+BackgroundSyncManager::BackgroundSyncRegistrations::BackgroundSyncRegistrations( |
+ BackgroundSyncRegistration::RegistrationId id_counter) |
+ : id_counter(id_counter) { |
+} |
+BackgroundSyncManager::BackgroundSyncRegistrations:: |
+ ~BackgroundSyncRegistrations() { |
+} |
+ |
+// 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(sync_registration.id == |
davidben
2015/03/25 16:01:09
Nit: DCHECK -> DCHECK_EQ
jkarlin
2015/03/25 19:24:18
Done.
|
+ BackgroundSyncRegistration::kInvalidRegistrationId); |
+ |
+ 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 std::string& sync_registration_name, |
+ BackgroundSyncRegistration::RegistrationId sync_registration_id, |
+ const StatusCallback& callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ 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_name, sync_registration_id, |
+ pending_callback)); |
+} |
+ |
+void BackgroundSyncManager::GetRegistration( |
+ const GURL& origin, |
+ int64 sw_registration_id, |
+ const std::string sync_registration_name, |
+ const StatusAndRegistrationCallback& callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ 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_name, pending_callback)); |
+} |
+ |
+BackgroundSyncManager::BackgroundSyncManager( |
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) |
+ : service_worker_context_(service_worker_context), weak_ptr_factory_(this) { |
+} |
+ |
+void BackgroundSyncManager::Init() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ DCHECK(!op_scheduler_.ScheduledOperations()); |
+ |
+ op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BackgroundSyncManager::InitImpl() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ GetDataFromBackend( |
+ kBackgroundSyncUserDataKey, |
+ base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void BackgroundSyncManager::InitDidGetDataFromBackend( |
+ 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)) { |
+ sw_to_registrations_map_[data.first] = BackgroundSyncRegistrations( |
+ registrations_proto.registration_id_counter()); |
+ BackgroundSyncRegistrations* registrations = |
+ &sw_to_registrations_map_[data.first]; |
+ |
+ for (int i = 0, max = registrations_proto.registration_size(); i < max; |
+ ++i) { |
+ const BackgroundSyncRegistrationProto& registration_proto = |
+ registrations_proto.registration(i); |
+ BackgroundSyncRegistration registration(registration_proto.id(), |
+ registration_proto.name()); |
davidben
2015/03/25 16:01:09
Optional: since this data comes from disk, is it w
jkarlin
2015/03/25 19:24:18
Done.
|
+ if (registration_proto.has_min_period()) |
+ registration.min_period = registration_proto.min_period(); |
+ registrations->name_to_registration_map[registration_proto.name()] = |
+ registration; |
+ } |
+ } |
+ } |
+ |
+ // 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) { |
+ BackgroundSyncRegistration existing_registration; |
+ if (HasRegistration(sw_registration_id, sync_registration.name, |
+ &existing_registration)) { |
+ if (existing_registration.Equals(sync_registration)) { |
davidben
2015/03/25 16:01:10
This check gives an interesting interaction with U
jkarlin
2015/03/25 19:24:18
Interesting. The race potential is there, sync fun
davidben
2015/03/25 19:42:03
Sounds good.
|
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback, ERROR_TYPE_OK, existing_registration)); |
+ return; |
+ } |
+ } |
+ |
+ BackgroundSyncRegistration new_registration = sync_registration; |
+ BackgroundSyncRegistrations* registrations = |
+ &sw_to_registrations_map_[sw_registration_id]; |
+ new_registration.id = registrations->id_counter++; |
+ |
+ AddRegistrationToMap(sw_registration_id, new_registration); |
+ |
+ StoreRegistrations( |
+ origin, sw_registration_id, |
+ base::Bind(&BackgroundSyncManager::RegisterDidStore, |
+ weak_ptr_factory_.GetWeakPtr(), sw_registration_id, |
+ new_registration, existing_registration, callback)); |
+} |
+ |
+bool BackgroundSyncManager::HasRegistration( |
+ int64 sw_registration_id, |
+ const std::string& sync_registration_name, |
+ BackgroundSyncRegistration* existing_registration) { |
+ SWIdToRegistrationsMap::iterator it = |
+ sw_to_registrations_map_.find(sw_registration_id); |
+ if (it == sw_to_registrations_map_.end()) |
+ return false; |
+ |
+ const BackgroundSyncRegistrations& registrations = it->second; |
+ const BackgroundSyncRegistrations::NameToRegistrationMap::const_iterator |
davidben
2015/03/25 16:01:09
Nit/optional: This type name is probably a prime c
jkarlin
2015/03/25 19:24:18
Done.
|
+ reg_iter = |
+ registrations.name_to_registration_map.find(sync_registration_name); |
+ if (reg_iter == registrations.name_to_registration_map.end()) |
+ return false; |
+ |
+ if (existing_registration) |
+ *existing_registration = reg_iter->second; |
+ |
+ return true; |
+} |
+ |
+void BackgroundSyncManager::StoreRegistrations( |
+ const GURL& origin, |
+ int64 sw_registration_id, |
+ const ServiceWorkerStorage::StatusCallback& callback) { |
+ // Serialize the data. |
+ const BackgroundSyncRegistrations& registrations = |
+ sw_to_registrations_map_[sw_registration_id]; |
+ BackgroundSyncRegistrationsProto registrations_proto; |
+ registrations_proto.set_registration_id_counter(registrations.id_counter); |
+ |
+ for (const auto& name_and_registration : |
+ registrations.name_to_registration_map) { |
+ const BackgroundSyncRegistration& registration = |
+ name_and_registration.second; |
+ BackgroundSyncRegistrationProto* registration_proto = |
+ registrations_proto.add_registration(); |
+ registration_proto->set_id(registration.id); |
+ registration_proto->set_name(registration.name); |
+ if (registration.min_period != 0) |
+ registration_proto->set_min_period(registration.min_period); |
+ } |
+ std::string serialized; |
+ bool success = registrations_proto.SerializeToString(&serialized); |
+ DCHECK(success); |
+ |
+ StoreDataInBackend(sw_registration_id, origin, kBackgroundSyncUserDataKey, |
+ serialized, callback); |
+} |
+ |
+void BackgroundSyncManager::RegisterDidStore( |
+ int64 sw_registration_id, |
+ const BackgroundSyncRegistration& sync_registration, |
davidben
2015/03/25 16:01:09
Nit: new_registration, to match the rename in the
jkarlin
2015/03/25 19:24:18
Done.
|
+ const BackgroundSyncRegistration& previous_registration, |
+ const StatusAndRegistrationCallback& callback, |
+ ServiceWorkerStatusCode status) { |
+ if (status != SERVICE_WORKER_OK) { |
+ // Restore the previous state. |
+ if (previous_registration.id != |
+ BackgroundSyncRegistration::kInvalidRegistrationId) { |
+ AddRegistrationToMap(sw_registration_id, previous_registration); |
+ } else { |
+ RemoveRegistrationFromMap(sw_registration_id, sync_registration.name, |
+ nullptr); |
+ } |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration())); |
+ return; |
+ } |
+ |
+ // TODO(jkarlin): Run the registration algorithm. |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, sync_registration)); |
+} |
+ |
+void BackgroundSyncManager::RemoveRegistrationFromMap( |
+ int64 sw_registration_id, |
+ const std::string& sync_registration_name, |
+ BackgroundSyncRegistration* old_registration) { |
davidben
2015/03/25 16:01:09
This never writes the old entry to old_registratio
jkarlin
2015/03/25 19:24:18
!!!!
Done.
|
+ DCHECK(HasRegistration(sw_registration_id, sync_registration_name, nullptr)); |
+ |
+ BackgroundSyncRegistrations* registrations = |
+ &sw_to_registrations_map_[sw_registration_id]; |
+ registrations->name_to_registration_map.erase(sync_registration_name); |
+} |
+ |
+void BackgroundSyncManager::AddRegistrationToMap( |
+ int64 sw_registration_id, |
+ const BackgroundSyncRegistration& sync_registration) { |
+ DCHECK(sw_registration_id != |
davidben
2015/03/25 16:01:09
Nit: DCHECK_NE
jkarlin
2015/03/25 19:24:18
Done.
|
+ BackgroundSyncRegistration::kInvalidRegistrationId); |
+ |
+ BackgroundSyncRegistrations* registrations = |
+ &sw_to_registrations_map_[sw_registration_id]; |
+ registrations->name_to_registration_map[sync_registration.name] = |
+ sync_registration; |
+} |
+ |
+void BackgroundSyncManager::StoreDataInBackend( |
+ int64 sw_registration_id, |
+ const GURL& origin, |
+ const std::string& key, |
+ const std::string& data, |
+ const ServiceWorkerStorage::StatusCallback& callback) { |
+ service_worker_context_->context()->storage()->StoreUserData( |
+ sw_registration_id, origin, key, data, callback); |
+} |
+ |
+void BackgroundSyncManager::GetDataFromBackend( |
+ const std::string& key, |
+ const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback& |
+ callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ service_worker_context_->context()->storage()->GetUserDataForAllRegistrations( |
+ key, callback); |
+} |
+ |
+void BackgroundSyncManager::UnregisterImpl( |
+ const GURL& origin, |
+ int64 sw_registration_id, |
+ const std::string& sync_registration_name, |
+ BackgroundSyncRegistration::RegistrationId sync_registration_id, |
+ const StatusCallback& callback) { |
+ BackgroundSyncRegistration existing_registration; |
+ if (!HasRegistration(sw_registration_id, sync_registration_name, |
+ &existing_registration) || |
+ existing_registration.id != sync_registration_id) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND)); |
+ return; |
+ } |
+ |
+ BackgroundSyncRegistration old_sync_registration; |
+ RemoveRegistrationFromMap(sw_registration_id, sync_registration_name, |
+ &old_sync_registration); |
+ |
+ StoreRegistrations( |
+ origin, sw_registration_id, |
+ base::Bind(&BackgroundSyncManager::UnregisterDidStore, |
+ weak_ptr_factory_.GetWeakPtr(), sw_registration_id, |
+ old_sync_registration, callback)); |
+} |
+ |
+void BackgroundSyncManager::UnregisterDidStore( |
+ int64 sw_registration_id, |
+ const BackgroundSyncRegistration& old_sync_registration, |
+ const StatusCallback& callback, |
+ ServiceWorkerStatusCode status) { |
+ if (status != SERVICE_WORKER_OK) { |
+ // Restore the previous state. |
+ AddRegistrationToMap(sw_registration_id, old_sync_registration); |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE)); |
+ return; |
+ } |
+ |
+ // TODO(jkarlin): Run the registration algorithm. |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(callback, ERROR_TYPE_OK)); |
+} |
+ |
+void BackgroundSyncManager::GetRegistrationImpl( |
+ const GURL& origin, |
+ int64 sw_registration_id, |
+ const std::string sync_registration_name, |
+ const StatusAndRegistrationCallback& callback) { |
davidben
2015/03/25 16:01:09
I think this function can just call HasRegistratio
jkarlin
2015/03/25 19:24:18
Done.
|
+ SWIdToRegistrationsMap::const_iterator it = |
+ sw_to_registrations_map_.find(sw_registration_id); |
+ |
+ if (it == sw_to_registrations_map_.end()) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND, |
+ BackgroundSyncRegistration())); |
+ return; |
+ } |
+ |
+ const BackgroundSyncRegistrations& registrations = it->second; |
+ const BackgroundSyncRegistrations::NameToRegistrationMap::const_iterator |
davidben
2015/03/25 16:01:10
Optional/nit: ditto about maybe using auto here.
jkarlin
2015/03/25 19:24:18
no longer needed
|
+ reg_iter = |
+ registrations.name_to_registration_map.find(sync_registration_name); |
+ if (reg_iter == registrations.name_to_registration_map.end()) { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND, |
+ BackgroundSyncRegistration())); |
+ return; |
+ } |
+ |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, reg_iter->second)); |
+} |
+ |
+void BackgroundSyncManager::PendingStatusAndRegistrationCallback( |
+ const StatusAndRegistrationCallback& callback, |
+ ErrorType error, |
+ const BackgroundSyncRegistration& sync_registration) { |
+ // The callback might delete this object, so hang onto a weak ptr to find out. |
+ base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr(); |
+ callback.Run(error, sync_registration); |
+ if (manager) |
+ op_scheduler_.CompleteOperationAndRunNext(); |
+} |
+ |
+void BackgroundSyncManager::PendingStatusCallback( |
+ const StatusCallback& callback, |
+ ErrorType error) { |
+ // The callback might delete this object, so hang onto a weak ptr to find out. |
+ base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr(); |
+ callback.Run(error); |
+ if (manager) |
+ op_scheduler_.CompleteOperationAndRunNext(); |
+} |
+ |
+} // namespace content |