/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
RefPtr<ServiceWorkerRegistration> registration = new ServiceWorkerRegistration(aWindow->AsGlobal(), aDescriptor); // This is not called from within the constructor, as it may call content code // which can cause the deletion of the registration, so we need to keep a // strong reference while calling it.
registration->UpdateState(aDescriptor);
RefPtr<ServiceWorkerRegistration> registration = new ServiceWorkerRegistration(aGlobal, aDescriptor); // This is not called from within the constructor, as it may call content code // which can cause the deletion of the registration, so we need to keep a // strong reference while calling it.
registration->UpdateState(aDescriptor);
void ServiceWorkerRegistration::RegistrationCleared() { // Its possible that the registration will fail to install and be // immediately removed. In that case we may never receive the // UpdateState() call if the actor was too slow to connect, etc. // Ensure that we force all our known actors to redundant so that // the appropriate statechange events are fired. If we got the // UpdateState() already then this will be a no-op.
UpdateStateInternal(Maybe<ServiceWorkerDescriptor>(),
Maybe<ServiceWorkerDescriptor>(),
Maybe<ServiceWorkerDescriptor>());
// Our underlying registration was removed from SWM, so we // will never get an updatefound event again. We can let // the object GC if content is not holding it alive.
IgnoreKeepAliveIfHasListenersFor(nsGkAtoms::onupdatefound);
}
// `ServiceWorker` objects are not exposed on worker threads yet, so calling // `ServiceWorkerRegistration::Get{Installing,Waiting,Active}` won't work. const Maybe<ServiceWorkerDescriptor> newestWorkerDescriptor =
mDescriptor.Newest();
// "If newestWorker is null, return a promise rejected with an // "InvalidStateError" DOMException and abort these steps." if (newestWorkerDescriptor.isNothing()) {
outer->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return outer.forget();
}
// "If the context object’s relevant settings object’s global object // globalObject is a ServiceWorkerGlobalScope object, and globalObject’s // associated service worker's state is "installing", return a promise // rejected with an "InvalidStateError" DOMException and abort these steps." if (!NS_IsMainThread()) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
if (aResult.type() ==
IPCServiceWorkerRegistrationDescriptorOrCopyableErrorResult::
TCopyableErrorResult) { // application layer error constauto& rv = aResult.get_CopyableErrorResult();
MOZ_DIAGNOSTIC_ASSERT(rv.Failed());
outer->MaybeReject(CopyableErrorResult(rv)); return;
} // success constauto& ipcDesc =
aResult.get_IPCServiceWorkerRegistrationDescriptor();
nsIGlobalObject* global = self->GetParentObject(); // It's possible this binding was detached from the global. In cases // where we use IPC with Promise callbacks, we use // DOMMozPromiseRequestHolder in order to auto-disconnect the promise // that would hold these callbacks. However in bug 1466681 we changed // this call to use (synchronous) callbacks because the use of // MozPromise introduced an additional runnable scheduling which made // it very difficult to maintain ordering required by the standard. // // If we were to delete this actor at the time of DETH detaching, we // would not need to do this check because the IPC callback of the // RemoteServiceWorkerRegistrationImpl lambdas would never occur. // However, its actors currently depend on asking the parent to delete // the actor for us. Given relaxations in the IPC lifecyle, we could // potentially issue a direct termination, but that requires additional // evaluation. if (!global) {
outer->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return;
}
RefPtr<ServiceWorkerRegistration> ref =
global->GetOrCreateServiceWorkerRegistration(
ServiceWorkerRegistrationDescriptor(ipcDesc)); if (!ref) {
outer->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return;
}
outer->MaybeResolve(ref);
},
[outer](ResponseRejectReason&& aReason) { // IPC layer error
outer->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
});
return outer.forget();
}
already_AddRefed<Promise> ServiceWorkerRegistration::Unregister(
ErrorResult& aRv) {
nsIGlobalObject* global = GetParentObject(); if (NS_WARN_IF(!global)) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr;
}
RefPtr<PushManager> ret = mPushManager; return ret.forget();
}
// https://notifications.spec.whatwg.org/#dom-serviceworkerregistration-shownotification
already_AddRefed<Promise> ServiceWorkerRegistration::ShowNotification(
JSContext* aCx, const nsAString& aTitle, const NotificationOptions& aOptions, ErrorResult& aRv) { // Step 1: Let global be this’s relevant global object.
nsIGlobalObject* global = GetParentObject(); if (!global) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr;
}
// Step 3: If this’s active worker is null, then reject promise with a // TypeError and return promise. // // Until we ship ServiceWorker objects on worker threads the active // worker will always be nullptr. So limit this check to main // thread for now. if (mDescriptor.GetActive().isNothing() && NS_IsMainThread()) {
aRv.ThrowTypeError<MSG_NO_ACTIVE_WORKER>(mDescriptor.Scope()); return nullptr;
}
void ServiceWorkerRegistration::MaybeScheduleUpdateFound( const Maybe<ServiceWorkerDescriptor>& aInstallingDescriptor) { // This function sets mScheduledUpdateFoundId to note when we were told about // a new installing worker. We rely on a call to MaybeDispatchUpdateFound via // ServiceWorkerRegistrationChild::RecvFireUpdateFound to trigger the properly // timed notification...
uint64_t newId = aInstallingDescriptor.isSome()
? aInstallingDescriptor.ref().Id()
: kInvalidUpdateFoundId;
// ...but the whole reason this logic exists is because SWRegistrations are // bootstrapped off of inherently stale descriptor snapshots and receive // catch-up updates once the actor is created and registered in the parent. // To handle the catch-up case where we need to generate a synthetic // updatefound that would otherwise be lost, we immediately flush here. if (mScheduledUpdateFoundId != kInvalidUpdateFoundId) { if (mScheduledUpdateFoundId == newId) { return;
}
MaybeDispatchUpdateFound();
MOZ_DIAGNOSTIC_ASSERT(mScheduledUpdateFoundId == kInvalidUpdateFoundId);
}
bool updateFound =
newId != kInvalidUpdateFoundId && mDispatchedUpdateFoundId != newId;
void ServiceWorkerRegistration::UpdateStateInternal( const Maybe<ServiceWorkerDescriptor>& aInstalling, const Maybe<ServiceWorkerDescriptor>& aWaiting, const Maybe<ServiceWorkerDescriptor>& aActive) { // Do this immediately as it may flush an already pending updatefound // event. In that case we want to fire the pending event before // modifying any of the registration properties.
MaybeScheduleUpdateFound(aInstalling);
// Move the currently exposed workers into a separate list // of "old" workers. We will then potentially add them // back to the registration properties below based on the // given descriptor. Any that are not restored will need // to be moved to the redundant state.
AutoTArray<RefPtr<ServiceWorker>, 3> oldWorkerList({
std::move(mInstallingWorker),
std::move(mWaitingWorker),
std::move(mActiveWorker),
});
// Its important that all state changes are actually applied before // dispatching any statechange events. Each ServiceWorker object // should be in the correct state and the ServiceWorkerRegistration // properties need to be set correctly as well. To accomplish this // we use a ScopeExit to dispatch any statechange events. auto scopeExit = MakeScopeExit([&] { // Check to see if any of the "old" workers was completely discarded. // Set these workers to the redundant state. for (auto& oldWorker : oldWorkerList) { if (!oldWorker || oldWorker == mInstallingWorker ||
oldWorker == mWaitingWorker || oldWorker == mActiveWorker) { continue;
}
// Check each worker to see if it needs a statechange event dispatched. if (mInstallingWorker) {
mInstallingWorker->MaybeDispatchStateChangeEvent();
} if (mWaitingWorker) {
mWaitingWorker->MaybeDispatchStateChangeEvent();
} if (mActiveWorker) {
mActiveWorker->MaybeDispatchStateChangeEvent();
}
// We also check the "old" workers to see if they need a statechange // event as well. Note, these may overlap with the known worker properties // above, but MaybeDispatchStateChangeEvent() will ignore duplicated calls. for (auto& oldWorker : oldWorkerList) { if (!oldWorker) { continue;
}
oldWorker->MaybeDispatchStateChangeEvent();
}
});
// Clear all workers if the registration has been detached from the global.
nsCOMPtr<nsIGlobalObject> global = GetParentObject(); if (!global) { return;
}
if (aActive.isSome()) { if ((mActiveWorker = global->GetOrCreateServiceWorker(aActive.ref()))) {
mActiveWorker->SetState(aActive.ref().State());
}
} else {
mActiveWorker = nullptr;
}
if (aWaiting.isSome()) { if ((mWaitingWorker = global->GetOrCreateServiceWorker(aWaiting.ref()))) {
mWaitingWorker->SetState(aWaiting.ref().State());
}
} else {
mWaitingWorker = nullptr;
}
if (aInstalling.isSome()) { if ((mInstallingWorker =
global->GetOrCreateServiceWorker(aInstalling.ref()))) {
mInstallingWorker->SetState(aInstalling.ref().State());
}
} else {
mInstallingWorker = nullptr;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.