1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/service_worker/service_worker_register_job.h"
9 #include "content/browser/service_worker/service_worker_job_coordinator.h"
10 #include "content/browser/service_worker/service_worker_registration.h"
11 #include "content/public/browser/browser_thread.h"
16 ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
17 ServiceWorkerStorage* storage,
18 EmbeddedWorkerRegistry* worker_registry,
19 ServiceWorkerJobCoordinator* coordinator,
21 const GURL& script_url,
22 RegistrationType type)
24 worker_registry_(worker_registry),
25 coordinator_(coordinator),
26 pending_version_(NULL),
28 script_url_(script_url),
30 weak_factory_(this) {}
32 ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {}
34 void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback,
36 // if we've created a pending version, associate source_provider it with
37 // that, otherwise queue it up
38 callbacks_.push_back(callback);
39 DCHECK(process_id != -1);
40 if (pending_version_) {
41 pending_version_->AddProcessToWorker(process_id);
43 pending_process_ids_.push_back(process_id);
47 void ServiceWorkerRegisterJob::Start() {
48 if (type_ == REGISTER)
54 bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJob* job) {
55 return job->type_ == type_ &&
56 (type_ == ServiceWorkerRegisterJob::UNREGISTER ||
57 job->script_url_ == script_url_);
60 void ServiceWorkerRegisterJob::StartRegister() {
61 // Set up a chain of callbacks, in reverse order. Each of these
62 // callbacks may be called asynchronously by the previous callback.
63 StatusCallback finish_registration(base::Bind(
64 &ServiceWorkerRegisterJob::RegisterComplete, weak_factory_.GetWeakPtr()));
66 RegistrationCallback start_worker(
67 base::Bind(&ServiceWorkerRegisterJob::StartWorkerAndContinue,
68 weak_factory_.GetWeakPtr(),
69 finish_registration));
71 UnregistrationCallback register_new(
72 base::Bind(&ServiceWorkerRegisterJob::RegisterPatternAndContinue,
73 weak_factory_.GetWeakPtr(),
76 ServiceWorkerStorage::FindRegistrationCallback unregister_old(
77 base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue,
78 weak_factory_.GetWeakPtr(),
81 storage_->FindRegistrationForPattern(pattern_, unregister_old);
84 void ServiceWorkerRegisterJob::StartUnregister() {
85 // Set up a chain of callbacks, in reverse order. Each of these
86 // callbacks may be called asynchronously by the previous callback.
87 UnregistrationCallback finish_unregistration(
88 base::Bind(&ServiceWorkerRegisterJob::UnregisterComplete,
89 weak_factory_.GetWeakPtr()));
91 ServiceWorkerStorage::FindRegistrationCallback unregister(
92 base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue,
93 weak_factory_.GetWeakPtr(),
94 finish_unregistration));
96 storage_->FindRegistrationForPattern(pattern_, unregister);
99 void ServiceWorkerRegisterJob::StartWorkerAndContinue(
100 const StatusCallback& callback,
101 ServiceWorkerStatusCode status,
102 const scoped_refptr<ServiceWorkerRegistration>& registration) {
103 if (registration->active_version()) {
104 // We have an active version, so we can complete immediately, even
105 // if the service worker isn't running.
106 callback.Run(registration, SERVICE_WORKER_OK);
110 pending_version_ = new ServiceWorkerVersion(
111 registration, worker_registry_, registration->next_version_id());
112 for (std::vector<int>::const_iterator it = pending_process_ids_.begin();
113 it != pending_process_ids_.end();
115 pending_version_->AddProcessToWorker(*it);
117 // The callback to watch "installation" actually fires as soon as
118 // the worker is up and running, just before the install event is
119 // dispatched. The job will continue to run even though the main
120 // callback has executed.
121 pending_version_->StartWorker(base::Bind(callback, registration));
123 // TODO(alecflett): Don't set the active version until just before
124 // the activate event is dispatched.
125 registration->set_active_version(pending_version_);
128 void ServiceWorkerRegisterJob::RegisterPatternAndContinue(
129 const RegistrationCallback& callback,
130 ServiceWorkerStatusCode previous_status) {
131 if (previous_status != SERVICE_WORKER_OK) {
132 BrowserThread::PostTask(
137 scoped_refptr<ServiceWorkerRegistration>()));
141 // TODO: Eventually RegisterInternal will be replaced by an asynchronous
142 // operation. Pass its resulting status through 'callback'.
143 scoped_refptr<ServiceWorkerRegistration> registration =
144 storage_->RegisterInternal(pattern_, script_url_);
146 BrowserThread::PostTask(BrowserThread::IO,
148 base::Bind(callback, SERVICE_WORKER_OK,
152 void ServiceWorkerRegisterJob::UnregisterPatternAndContinue(
153 const UnregistrationCallback& callback,
155 ServiceWorkerStatusCode previous_status,
156 const scoped_refptr<ServiceWorkerRegistration>& previous_registration) {
158 // The previous registration may not exist, which is ok.
159 if (previous_status == SERVICE_WORKER_OK && found &&
160 (script_url_.is_empty() ||
161 previous_registration->script_url() != script_url_)) {
162 // TODO: Eventually UnregisterInternal will be replaced by an
163 // asynchronous operation. Pass its resulting status though
165 storage_->UnregisterInternal(pattern_);
166 DCHECK(previous_registration->is_shutdown());
168 // TODO(alecflett): We have an existing registration, we should
169 // schedule an update.
171 BrowserThread::PostTask(
172 BrowserThread::IO, FROM_HERE, base::Bind(callback, previous_status));
175 void ServiceWorkerRegisterJob::RunCallbacks(
176 ServiceWorkerStatusCode status,
177 const scoped_refptr<ServiceWorkerRegistration>& registration) {
178 for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin();
179 it != callbacks_.end();
181 it->Run(status, registration);
185 void ServiceWorkerRegisterJob::RegisterComplete(
186 const scoped_refptr<ServiceWorkerRegistration>& registration,
187 ServiceWorkerStatusCode start_status) {
188 RunCallbacks(start_status, registration);
189 coordinator_->FinishJob(pattern_, this);
192 void ServiceWorkerRegisterJob::UnregisterComplete(
193 ServiceWorkerStatusCode status) {
194 RunCallbacks(status, NULL);
195 coordinator_->FinishJob(pattern_, this);
198 } // namespace content