Bug 1424338 P1 Implement ClientManager::MatchAll() to support clients.matchAll() WebAPI. r=baku

This commit is contained in:
Ben Kelly 2017-12-08 14:46:42 -05:00
parent 491e62af53
commit 783e26e13e
8 changed files with 196 additions and 0 deletions

View File

@ -67,6 +67,19 @@ struct ClientControlledArgs
IPCServiceWorkerDescriptor serviceWorker;
};
union ClientEndPoint
{
IPCClientInfo;
IPCServiceWorkerDescriptor;
};
struct ClientMatchAllArgs
{
ClientEndPoint endpoint;
ClientType type;
bool includeUncontrolled;
};
struct ClientGetInfoAndStateArgs
{
nsID id;
@ -80,9 +93,15 @@ struct ClientOpenWindowArgs
union ClientOpConstructorArgs
{
ClientControlledArgs;
ClientMatchAllArgs;
ClientGetInfoAndStateArgs;
};
struct ClientList
{
ClientInfoAndState[] values;
};
struct ClientNavigateOpConstructorArgs
{
};
@ -91,6 +110,7 @@ union ClientOpResult
{
nsresult;
ClientInfoAndState;
ClientList;
};
} // namespace dom

View File

@ -257,6 +257,15 @@ ClientManager::CreateHandle(const ClientInfo& aClientInfo,
return mgr->CreateHandleInternal(aClientInfo, aSerialEventTarget);
}
// static
RefPtr<ClientOpPromise>
ClientManager::MatchAll(const ClientMatchAllArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget)
{
RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
return mgr->StartOp(aArgs, aSerialEventTarget);
}
// static
RefPtr<ClientOpPromise>
ClientManager::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs,

View File

@ -22,6 +22,7 @@ class ClientGetInfoAndStateArgs;
class ClientHandle;
class ClientInfo;
class ClientManagerChild;
class ClientMatchAllArgs;
class ClientOpConstructorArgs;
class ClientSource;
enum class ClientType : uint8_t;
@ -94,6 +95,9 @@ public:
CreateHandle(const ClientInfo& aClientInfo,
nsISerialEventTarget* aSerialEventTarget);
static RefPtr<ClientOpPromise>
MatchAll(const ClientMatchAllArgs& aArgs, nsISerialEventTarget* aTarget);
static RefPtr<ClientOpPromise>
GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs,
nsISerialEventTarget* aSerialEventTarget);

View File

@ -48,6 +48,12 @@ void
ClientManagerOpParent::Init(const ClientOpConstructorArgs& aArgs)
{
switch (aArgs.type()) {
case ClientOpConstructorArgs::TClientMatchAllArgs:
{
DoServiceOp(&ClientManagerService::MatchAll,
aArgs.get_ClientMatchAllArgs());
break;
}
case ClientOpConstructorArgs::TClientGetInfoAndStateArgs:
{
DoServiceOp(&ClientManagerService::GetInfoAndState,

View File

@ -302,6 +302,151 @@ ClientManagerService::RemoveManager(ClientManagerParent* aManager)
MOZ_ASSERT(removed);
}
namespace
{
class PromiseListHolder final
{
RefPtr<ClientOpPromise::Private> mResultPromise;
nsTArray<RefPtr<ClientOpPromise>> mPromiseList;
nsTArray<ClientInfoAndState> mResultList;
uint32_t mOutstandingPromiseCount;
void
ProcessSuccess(const ClientInfoAndState& aResult)
{
mResultList.AppendElement(aResult);
ProcessCompletion();
}
void
ProcessCompletion()
{
MOZ_DIAGNOSTIC_ASSERT(mOutstandingPromiseCount > 0);
mOutstandingPromiseCount -= 1;
MaybeFinish();
}
~PromiseListHolder() = default;
public:
PromiseListHolder()
: mResultPromise(new ClientOpPromise::Private(__func__))
, mOutstandingPromiseCount(0)
{
}
already_AddRefed<ClientOpPromise>
GetResultPromise()
{
RefPtr<PromiseListHolder> kungFuDeathGrip = this;
mResultPromise->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[kungFuDeathGrip] (const ClientOpResult& aResult) { },
[kungFuDeathGrip] (nsresult aResult) { });
RefPtr<ClientOpPromise> ref = mResultPromise;
return ref.forget();
}
void
AddPromise(RefPtr<ClientOpPromise>&& aPromise)
{
mPromiseList.AppendElement(Move(aPromise));
MOZ_DIAGNOSTIC_ASSERT(mPromiseList.LastElement());
mOutstandingPromiseCount += 1;
RefPtr<PromiseListHolder> self(this);
mPromiseList.LastElement()->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[self] (const ClientOpResult& aResult) {
// TODO: This is pretty clunky. Try to figure out a better
// wait for MatchAll() and Claim() to share this code
// even though they expect different return values.
if (aResult.type() == ClientOpResult::TClientInfoAndState) {
self->ProcessSuccess(aResult.get_ClientInfoAndState());
} else {
self->ProcessCompletion();
}
}, [self] (nsresult aResult) {
self->ProcessCompletion();
});
}
void
MaybeFinish()
{
if (!mOutstandingPromiseCount) {
mResultPromise->Resolve(mResultList, __func__);
}
}
NS_INLINE_DECL_REFCOUNTING(PromiseListHolder)
};
} // anonymous namespace
RefPtr<ClientOpPromise>
ClientManagerService::MatchAll(const ClientMatchAllArgs& aArgs)
{
AssertIsOnBackgroundThread();
const ClientEndPoint& endpoint = aArgs.endpoint();
const PrincipalInfo& principalInfo =
endpoint.type() == ClientEndPoint::TIPCClientInfo
? endpoint.get_IPCClientInfo().principalInfo()
: endpoint.get_IPCServiceWorkerDescriptor().principalInfo();
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
ClientSourceParent* source = iter.UserData();
MOZ_DIAGNOSTIC_ASSERT(source);
if (source->IsFrozen() || !source->ExecutionReady()) {
continue;
}
if (aArgs.type() != ClientType::All &&
source->Info().Type() != aArgs.type()) {
continue;
}
if (!MatchPrincipalInfo(source->Info().PrincipalInfo(), principalInfo)) {
continue;
}
if (!aArgs.includeUncontrolled()) {
if (endpoint.type() != ClientEndPoint::TIPCServiceWorkerDescriptor) {
continue;
}
const Maybe<ServiceWorkerDescriptor>& controller =
source->GetController();
if (controller.isNothing()) {
continue;
}
const IPCServiceWorkerDescriptor& serviceWorker =
endpoint.get_IPCServiceWorkerDescriptor();
if(controller.ref().Id() != serviceWorker.id() ||
controller.ref().Scope() != serviceWorker.scope()) {
continue;
}
}
promiseList->AddPromise(
source->StartOp(Move(ClientGetInfoAndStateArgs(source->Info().Id(),
source->Info().PrincipalInfo()))));
}
// Maybe finish the promise now in case we didn't find any matching clients.
promiseList->MaybeFinish();
return promiseList->GetResultPromise();
}
RefPtr<ClientOpPromise>
ClientManagerService::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs)
{

View File

@ -59,6 +59,9 @@ public:
void
RemoveManager(ClientManagerParent* aManager);
RefPtr<ClientOpPromise>
MatchAll(const ClientMatchAllArgs& aArgs);
RefPtr<ClientOpPromise>
GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs);

View File

@ -225,6 +225,12 @@ ClientSourceParent::ExecutionReady() const
return mExecutionReady;
}
const Maybe<ServiceWorkerDescriptor>&
ClientSourceParent::GetController() const
{
return mController;
}
void
ClientSourceParent::AttachHandle(ClientHandleParent* aClientHandle)
{

View File

@ -70,6 +70,9 @@ public:
bool
ExecutionReady() const;
const Maybe<ServiceWorkerDescriptor>&
GetController() const;
void
AttachHandle(ClientHandleParent* aClientSource);