first commit
This commit is contained in:
206
node_modules/chromium-bidi/lib/cjs/bidiMapper/domains/session/SubscriptionManager.js
generated
vendored
Normal file
206
node_modules/chromium-bidi/lib/cjs/bidiMapper/domains/session/SubscriptionManager.js
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
"use strict";
|
||||
/**
|
||||
* Copyright 2022 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SubscriptionManager = exports.unrollEvents = exports.cartesianProduct = void 0;
|
||||
const protocol_js_1 = require("../../../protocol/protocol.js");
|
||||
const events_js_1 = require("./events.js");
|
||||
/**
|
||||
* Returns the cartesian product of the given arrays.
|
||||
*
|
||||
* Example:
|
||||
* cartesian([1, 2], ['a', 'b']); => [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
|
||||
*/
|
||||
function cartesianProduct(...a) {
|
||||
return a.reduce((a, b) => a.flatMap((d) => b.map((e) => [d, e].flat())));
|
||||
}
|
||||
exports.cartesianProduct = cartesianProduct;
|
||||
/** Expands "AllEvents" events into atomic events. */
|
||||
function unrollEvents(events) {
|
||||
const allEvents = new Set();
|
||||
function addEvents(events) {
|
||||
for (const event of events) {
|
||||
allEvents.add(event);
|
||||
}
|
||||
}
|
||||
for (const event of events) {
|
||||
switch (event) {
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.BrowsingContext:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.BrowsingContext.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Log:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Log.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Network:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Network.EventNames));
|
||||
break;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Script:
|
||||
addEvents(Object.values(protocol_js_1.ChromiumBidi.Script.EventNames));
|
||||
break;
|
||||
default:
|
||||
allEvents.add(event);
|
||||
}
|
||||
}
|
||||
return [...allEvents.values()];
|
||||
}
|
||||
exports.unrollEvents = unrollEvents;
|
||||
class SubscriptionManager {
|
||||
#subscriptionPriority = 0;
|
||||
// BrowsingContext `null` means the event has subscription across all the
|
||||
// browsing contexts.
|
||||
// Channel `null` means no `channel` should be added.
|
||||
#channelToContextToEventMap = new Map();
|
||||
#browsingContextStorage;
|
||||
constructor(browsingContextStorage) {
|
||||
this.#browsingContextStorage = browsingContextStorage;
|
||||
}
|
||||
getChannelsSubscribedToEvent(eventMethod, contextId) {
|
||||
const prioritiesAndChannels = Array.from(this.#channelToContextToEventMap.keys())
|
||||
.map((channel) => ({
|
||||
priority: this.#getEventSubscriptionPriorityForChannel(eventMethod, contextId, channel),
|
||||
channel,
|
||||
}))
|
||||
.filter(({ priority }) => priority !== null);
|
||||
// Sort channels by priority.
|
||||
return prioritiesAndChannels
|
||||
.sort((a, b) => a.priority - b.priority)
|
||||
.map(({ channel }) => channel);
|
||||
}
|
||||
#getEventSubscriptionPriorityForChannel(eventMethod, contextId, channel) {
|
||||
const contextToEventMap = this.#channelToContextToEventMap.get(channel);
|
||||
if (contextToEventMap === undefined) {
|
||||
return null;
|
||||
}
|
||||
const maybeTopLevelContextId = this.#browsingContextStorage.findTopLevelContextId(contextId);
|
||||
// `null` covers global subscription.
|
||||
const relevantContexts = [...new Set([null, maybeTopLevelContextId])];
|
||||
// Get all the subscription priorities.
|
||||
const priorities = relevantContexts
|
||||
.map((context) => {
|
||||
// Get the priority for exact event name
|
||||
const priority = contextToEventMap.get(context)?.get(eventMethod);
|
||||
// For CDP we can't provide specific event name when subscribing
|
||||
// to the module directly.
|
||||
// Because of that we need to see event `cdp` exits in the map.
|
||||
if ((0, events_js_1.isCdpEvent)(eventMethod)) {
|
||||
const cdpPriority = contextToEventMap
|
||||
.get(context)
|
||||
?.get(protocol_js_1.ChromiumBidi.BiDiModule.Cdp);
|
||||
// If we subscribe to the event directly and `cdp` module as well
|
||||
// priority will be different we take minimal priority
|
||||
return priority && cdpPriority
|
||||
? Math.min(priority, cdpPriority)
|
||||
: // At this point we know that we have subscribed
|
||||
// to only one of the two
|
||||
priority ?? cdpPriority;
|
||||
}
|
||||
return priority;
|
||||
})
|
||||
.filter((p) => p !== undefined);
|
||||
if (priorities.length === 0) {
|
||||
// Not subscribed, return null.
|
||||
return null;
|
||||
}
|
||||
// Return minimal priority.
|
||||
return Math.min(...priorities);
|
||||
}
|
||||
subscribe(event, contextId, channel) {
|
||||
// All the subscriptions are handled on the top-level contexts.
|
||||
contextId = this.#browsingContextStorage.findTopLevelContextId(contextId);
|
||||
// Check if subscribed event is a whole module
|
||||
switch (event) {
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.BrowsingContext:
|
||||
Object.values(protocol_js_1.ChromiumBidi.BrowsingContext.EventNames).map((specificEvent) => this.subscribe(specificEvent, contextId, channel));
|
||||
return;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Log:
|
||||
Object.values(protocol_js_1.ChromiumBidi.Log.EventNames).map((specificEvent) => this.subscribe(specificEvent, contextId, channel));
|
||||
return;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Network:
|
||||
Object.values(protocol_js_1.ChromiumBidi.Network.EventNames).map((specificEvent) => this.subscribe(specificEvent, contextId, channel));
|
||||
return;
|
||||
case protocol_js_1.ChromiumBidi.BiDiModule.Script:
|
||||
Object.values(protocol_js_1.ChromiumBidi.Script.EventNames).map((specificEvent) => this.subscribe(specificEvent, contextId, channel));
|
||||
return;
|
||||
default:
|
||||
// Intentionally left empty.
|
||||
}
|
||||
if (!this.#channelToContextToEventMap.has(channel)) {
|
||||
this.#channelToContextToEventMap.set(channel, new Map());
|
||||
}
|
||||
const contextToEventMap = this.#channelToContextToEventMap.get(channel);
|
||||
if (!contextToEventMap.has(contextId)) {
|
||||
contextToEventMap.set(contextId, new Map());
|
||||
}
|
||||
const eventMap = contextToEventMap.get(contextId);
|
||||
// Do not re-subscribe to events to keep the priority.
|
||||
if (eventMap.has(event)) {
|
||||
return;
|
||||
}
|
||||
eventMap.set(event, this.#subscriptionPriority++);
|
||||
}
|
||||
/**
|
||||
* Unsubscribes atomically from all events in the given contexts and channel.
|
||||
*/
|
||||
unsubscribeAll(events, contextIds, channel) {
|
||||
// Assert all contexts are known.
|
||||
for (const contextId of contextIds) {
|
||||
if (contextId !== null) {
|
||||
this.#browsingContextStorage.getContext(contextId);
|
||||
}
|
||||
}
|
||||
const eventContextPairs = cartesianProduct(unrollEvents(events), contextIds);
|
||||
// Assert all unsubscriptions are valid.
|
||||
// If any of the unsubscriptions are invalid, do not unsubscribe from anything.
|
||||
eventContextPairs
|
||||
.map(([event, contextId]) => this.#checkUnsubscribe(event, contextId, channel))
|
||||
.forEach((unsubscribe) => unsubscribe());
|
||||
}
|
||||
/**
|
||||
* Unsubscribes from the event in the given context and channel.
|
||||
* Syntactic sugar for "unsubscribeAll".
|
||||
*/
|
||||
unsubscribe(eventName, contextId, channel) {
|
||||
this.unsubscribeAll([eventName], [contextId], channel);
|
||||
}
|
||||
#checkUnsubscribe(event, contextId, channel) {
|
||||
// All the subscriptions are handled on the top-level contexts.
|
||||
contextId = this.#browsingContextStorage.findTopLevelContextId(contextId);
|
||||
if (!this.#channelToContextToEventMap.has(channel)) {
|
||||
throw new protocol_js_1.InvalidArgumentException(`Cannot unsubscribe from ${event}, ${contextId === null ? 'null' : contextId}. No subscription found.`);
|
||||
}
|
||||
const contextToEventMap = this.#channelToContextToEventMap.get(channel);
|
||||
if (!contextToEventMap.has(contextId)) {
|
||||
throw new protocol_js_1.InvalidArgumentException(`Cannot unsubscribe from ${event}, ${contextId === null ? 'null' : contextId}. No subscription found.`);
|
||||
}
|
||||
const eventMap = contextToEventMap.get(contextId);
|
||||
if (!eventMap.has(event)) {
|
||||
throw new protocol_js_1.InvalidArgumentException(`Cannot unsubscribe from ${event}, ${contextId === null ? 'null' : contextId}. No subscription found.`);
|
||||
}
|
||||
return () => {
|
||||
eventMap.delete(event);
|
||||
// Clean up maps if empty.
|
||||
if (eventMap.size === 0) {
|
||||
contextToEventMap.delete(event);
|
||||
}
|
||||
if (contextToEventMap.size === 0) {
|
||||
this.#channelToContextToEventMap.delete(channel);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.SubscriptionManager = SubscriptionManager;
|
||||
//# sourceMappingURL=SubscriptionManager.js.map
|
||||
Reference in New Issue
Block a user