add hw2
This commit is contained in:
235
node_modules/chromium-bidi/lib/cjs/bidiMapper/modules/script/ChannelProxy.js
generated
vendored
Normal file
235
node_modules/chromium-bidi/lib/cjs/bidiMapper/modules/script/ChannelProxy.js
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
"use strict";
|
||||
/*
|
||||
* Copyright 2023 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.ChannelProxy = void 0;
|
||||
const protocol_js_1 = require("../../../protocol/protocol.js");
|
||||
const log_js_1 = require("../../../utils/log.js");
|
||||
const uuid_js_1 = require("../../../utils/uuid.js");
|
||||
/**
|
||||
* Used to send messages from realm to BiDi user.
|
||||
*/
|
||||
class ChannelProxy {
|
||||
#properties;
|
||||
#id = (0, uuid_js_1.uuidv4)();
|
||||
#logger;
|
||||
constructor(channel, logger) {
|
||||
this.#properties = channel;
|
||||
this.#logger = logger;
|
||||
}
|
||||
/**
|
||||
* Creates a channel proxy in the given realm, initialises listener and
|
||||
* returns a handle to `sendMessage` delegate.
|
||||
*/
|
||||
async init(realm, eventManager) {
|
||||
const channelHandle = await ChannelProxy.#createAndGetHandleInRealm(realm);
|
||||
const sendMessageHandle = await ChannelProxy.#createSendMessageHandle(realm, channelHandle);
|
||||
void this.#startListener(realm, channelHandle, eventManager);
|
||||
return sendMessageHandle;
|
||||
}
|
||||
/** Gets a ChannelProxy from window and returns its handle. */
|
||||
async startListenerFromWindow(realm, eventManager) {
|
||||
try {
|
||||
const channelHandle = await this.#getHandleFromWindow(realm);
|
||||
void this.#startListener(realm, channelHandle, eventManager);
|
||||
}
|
||||
catch (error) {
|
||||
this.#logger?.(log_js_1.LogType.debugError, error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Evaluation string which creates a ChannelProxy object on the client side.
|
||||
*/
|
||||
static #createChannelProxyEvalStr() {
|
||||
const functionStr = String(() => {
|
||||
const queue = [];
|
||||
let queueNonEmptyResolver = null;
|
||||
return {
|
||||
/**
|
||||
* Gets a promise, which is resolved as soon as a message occurs
|
||||
* in the queue.
|
||||
*/
|
||||
async getMessage() {
|
||||
const onMessage = queue.length > 0
|
||||
? Promise.resolve()
|
||||
: new Promise((resolve) => {
|
||||
queueNonEmptyResolver = resolve;
|
||||
});
|
||||
await onMessage;
|
||||
return queue.shift();
|
||||
},
|
||||
/**
|
||||
* Adds a message to the queue.
|
||||
* Resolves the pending promise if needed.
|
||||
*/
|
||||
sendMessage(message) {
|
||||
queue.push(message);
|
||||
if (queueNonEmptyResolver !== null) {
|
||||
queueNonEmptyResolver();
|
||||
queueNonEmptyResolver = null;
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
return `(${functionStr})()`;
|
||||
}
|
||||
/** Creates a ChannelProxy in the given realm. */
|
||||
static async #createAndGetHandleInRealm(realm) {
|
||||
const createChannelHandleResult = await realm.cdpClient.sendCommand('Runtime.evaluate', {
|
||||
expression: this.#createChannelProxyEvalStr(),
|
||||
contextId: realm.executionContextId,
|
||||
serializationOptions: {
|
||||
serialization: "idOnly" /* Protocol.Runtime.SerializationOptionsSerialization.IdOnly */,
|
||||
},
|
||||
});
|
||||
if (createChannelHandleResult.exceptionDetails ||
|
||||
createChannelHandleResult.result.objectId === undefined) {
|
||||
throw new Error(`Cannot create channel`);
|
||||
}
|
||||
return createChannelHandleResult.result.objectId;
|
||||
}
|
||||
/** Gets a handle to `sendMessage` delegate from the ChannelProxy handle. */
|
||||
static async #createSendMessageHandle(realm, channelHandle) {
|
||||
const sendMessageArgResult = await realm.cdpClient.sendCommand('Runtime.callFunctionOn', {
|
||||
functionDeclaration: String((channelHandle) => {
|
||||
return channelHandle.sendMessage;
|
||||
}),
|
||||
arguments: [{ objectId: channelHandle }],
|
||||
executionContextId: realm.executionContextId,
|
||||
serializationOptions: {
|
||||
serialization: "idOnly" /* Protocol.Runtime.SerializationOptionsSerialization.IdOnly */,
|
||||
},
|
||||
});
|
||||
// TODO: check for exceptionDetails.
|
||||
return sendMessageArgResult.result.objectId;
|
||||
}
|
||||
/** Starts listening for the channel events of the provided ChannelProxy. */
|
||||
async #startListener(realm, channelHandle, eventManager) {
|
||||
// noinspection InfiniteLoopJS
|
||||
for (;;) {
|
||||
try {
|
||||
const message = await realm.cdpClient.sendCommand('Runtime.callFunctionOn', {
|
||||
functionDeclaration: String(async (channelHandle) => await channelHandle.getMessage()),
|
||||
arguments: [
|
||||
{
|
||||
objectId: channelHandle,
|
||||
},
|
||||
],
|
||||
awaitPromise: true,
|
||||
executionContextId: realm.executionContextId,
|
||||
serializationOptions: {
|
||||
serialization: "deep" /* Protocol.Runtime.SerializationOptionsSerialization.Deep */,
|
||||
maxDepth: this.#properties.serializationOptions?.maxObjectDepth ??
|
||||
undefined,
|
||||
},
|
||||
});
|
||||
if (message.exceptionDetails) {
|
||||
throw new Error('Runtime.callFunctionOn in ChannelProxy', {
|
||||
cause: message.exceptionDetails,
|
||||
});
|
||||
}
|
||||
for (const browsingContext of realm.associatedBrowsingContexts) {
|
||||
eventManager.registerEvent({
|
||||
type: 'event',
|
||||
method: protocol_js_1.ChromiumBidi.Script.EventNames.Message,
|
||||
params: {
|
||||
channel: this.#properties.channel,
|
||||
data: realm.cdpToBidiValue(message, this.#properties.ownership ?? "none" /* Script.ResultOwnership.None */),
|
||||
source: realm.source,
|
||||
},
|
||||
}, browsingContext.id);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
// If an error is thrown, then the channel is permanently broken, so we
|
||||
// exit the loop.
|
||||
this.#logger?.(log_js_1.LogType.debugError, error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns a handle of ChannelProxy from window's property which was set there
|
||||
* by `getEvalInWindowStr`. If window property is not set yet, sets a promise
|
||||
* resolver to the window property, so that `getEvalInWindowStr` can resolve
|
||||
* the promise later on with the channel.
|
||||
* This is needed because `getEvalInWindowStr` can be called before or
|
||||
* after this method.
|
||||
*/
|
||||
async #getHandleFromWindow(realm) {
|
||||
const channelHandleResult = await realm.cdpClient.sendCommand('Runtime.callFunctionOn', {
|
||||
functionDeclaration: String((id) => {
|
||||
const w = window;
|
||||
if (w[id] === undefined) {
|
||||
// The channelProxy is not created yet. Create a promise, put the
|
||||
// resolver to window property and return the promise.
|
||||
// `getEvalInWindowStr` will resolve the promise later.
|
||||
return new Promise((resolve) => (w[id] = resolve));
|
||||
}
|
||||
// The channelProxy is already created by `getEvalInWindowStr` and
|
||||
// is set into window property. Return it.
|
||||
const channelProxy = w[id];
|
||||
delete w[id];
|
||||
return channelProxy;
|
||||
}),
|
||||
arguments: [{ value: this.#id }],
|
||||
executionContextId: realm.executionContextId,
|
||||
awaitPromise: true,
|
||||
serializationOptions: {
|
||||
serialization: "idOnly" /* Protocol.Runtime.SerializationOptionsSerialization.IdOnly */,
|
||||
},
|
||||
});
|
||||
if (channelHandleResult.exceptionDetails !== undefined ||
|
||||
channelHandleResult.result.objectId === undefined) {
|
||||
throw new Error(`ChannelHandle not found in window["${this.#id}"]`);
|
||||
}
|
||||
return channelHandleResult.result.objectId;
|
||||
}
|
||||
/**
|
||||
* String to be evaluated to create a ProxyChannel and put it to window.
|
||||
* Returns the delegate `sendMessage`. Used to provide an argument for preload
|
||||
* script. Does the following:
|
||||
* 1. Creates a ChannelProxy.
|
||||
* 2. Puts the ChannelProxy to window['${this.#id}'] or resolves the promise
|
||||
* by calling delegate stored in window['${this.#id}'].
|
||||
* This is needed because `#getHandleFromWindow` can be called before or
|
||||
* after this method.
|
||||
* 3. Returns the delegate `sendMessage` of the created ChannelProxy.
|
||||
*/
|
||||
getEvalInWindowStr() {
|
||||
const delegate = String((id, channelProxy) => {
|
||||
const w = window;
|
||||
if (w[id] === undefined) {
|
||||
// `#getHandleFromWindow` is not initialized yet, and will get the
|
||||
// channelProxy later.
|
||||
w[id] = channelProxy;
|
||||
}
|
||||
else {
|
||||
// `#getHandleFromWindow` is already set a delegate to window property
|
||||
// and is waiting for it to be called with the channelProxy.
|
||||
w[id](channelProxy);
|
||||
delete w[id];
|
||||
}
|
||||
return channelProxy.sendMessage;
|
||||
});
|
||||
const channelProxyEval = ChannelProxy.#createChannelProxyEvalStr();
|
||||
return `(${delegate})('${this.#id}',${channelProxyEval})`;
|
||||
}
|
||||
}
|
||||
exports.ChannelProxy = ChannelProxy;
|
||||
//# sourceMappingURL=ChannelProxy.js.map
|
||||
Reference in New Issue
Block a user