chore(rpc): remove some paths from the channel (#2934)

This commit is contained in:
Pavel Feldman 2020-07-14 10:51:37 -07:00 committed by GitHub
parent cc8fe5a763
commit d5bd459986
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 137 additions and 14 deletions

View file

@ -22,7 +22,6 @@ export type Binary = string;
export interface Channel extends EventEmitter {
}
export interface PlaywrightChannel extends Channel {
}
export type PlaywrightInitializer = {
@ -181,8 +180,8 @@ export interface FrameChannel extends Channel {
evalOnSelector(params: { selector: string; expression: string, isFunction: boolean, arg: any} & PageAttribution): Promise<any>;
evalOnSelectorAll(params: { selector: string; expression: string, isFunction: boolean, arg: any} & PageAttribution): Promise<any>;
addScriptTag(params: { url?: string | undefined, path?: string | undefined, content?: string | undefined, type?: string | undefined} & PageAttribution): Promise<ElementHandleChannel>;
addStyleTag(params: { url?: string | undefined, path?: string | undefined, content?: string | undefined} & PageAttribution): Promise<ElementHandleChannel>;
addScriptTag(params: { url?: string, content?: string, type?: string } & PageAttribution): Promise<ElementHandleChannel>;
addStyleTag(params: { url?: string, content?: string } & PageAttribution): Promise<ElementHandleChannel>;
check(params: { selector: string, force?: boolean, noWaitAfter?: boolean } & types.TimeoutOptions & PageAttribution): Promise<void>;
click(params: { selector: string, force?: boolean, noWaitAfter?: boolean } & types.PointerActionOptions & types.MouseClickOptions & types.TimeoutOptions & PageAttribution): Promise<void>;
content(): Promise<string>;
@ -352,6 +351,7 @@ export type DialogInitializer = {
export interface DownloadChannel extends Channel {
path(): Promise<string | null>;
failure(): Promise<string | null>;
stream(): Promise<StreamChannel | null>;
delete(): Promise<void>;
}
export type DownloadInitializer = {
@ -360,6 +360,13 @@ export type DownloadInitializer = {
};
export interface StreamChannel extends Channel {
read(params: { size?: number }): Promise<Binary>;
}
export type StreamInitializer = {
}
// Chromium-specific.
export interface CDPSessionChannel extends Channel {
on(event: 'event', callback: (params: { method: string, params?: Object }) => void): this;
@ -370,7 +377,6 @@ export interface CDPSessionChannel extends Channel {
}
export type CDPSessionInitializer = {};
export type PDFOptions = {
scale?: number,
displayHeaderFooter?: boolean,
@ -384,7 +390,6 @@ export type PDFOptions = {
height?: string,
preferCSSPageSize?: boolean,
margin?: {top?: string, bottom?: string, left?: string, right?: string},
path?: string,
};

View file

@ -37,6 +37,7 @@ import { Channel } from '../channels';
import { ChromiumBrowser } from './chromiumBrowser';
import { ChromiumBrowserContext } from './chromiumBrowserContext';
import { Selectors } from './selectors';
import { Stream } from './stream';
class Root extends ChannelOwner<Channel, {}> {
constructor(connection: Connection) {
@ -201,6 +202,9 @@ export class Connection {
case 'request':
result = new Request(parent, type, guid, initializer);
break;
case 'stream':
result = new Stream(parent, type, guid, initializer);
break;
case 'response':
result = new Response(parent, type, guid, initializer);
break;

View file

@ -14,10 +14,10 @@
* limitations under the License.
*/
import * as fs from 'fs';
import { DownloadChannel, DownloadInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { Readable } from 'stream';
import { Stream } from './stream';
export class Download extends ChannelOwner<DownloadChannel, DownloadInitializer> {
static from(download: DownloadChannel): Download {
@ -45,8 +45,11 @@ export class Download extends ChannelOwner<DownloadChannel, DownloadInitializer>
}
async createReadStream(): Promise<Readable | null> {
const fileName = await this.path();
return fileName ? fs.createReadStream(fileName) : null;
const s = await this._channel.stream();
if (!s)
return null;
const stream = Stream.from(s);
return stream.stream();
}
async delete(): Promise<void> {

View file

@ -22,13 +22,17 @@ import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { ElementHandle, convertSelectOptionValues, convertInputFiles } from './elementHandle';
import { JSHandle, Func1, FuncOn, SmartHandle, serializeArgument, parseResult } from './jsHandle';
import * as fs from 'fs';
import * as network from './network';
import * as util from 'util';
import { Page } from './page';
import { EventEmitter } from 'events';
import { Waiter } from './waiter';
import { Events } from '../../events';
import { TimeoutError } from '../../errors';
const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
export type GotoOptions = types.NavigateOptions & {
referer?: string,
};
@ -174,10 +178,18 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
}
async addScriptTag(options: { url?: string, path?: string, content?: string, type?: string }): Promise<ElementHandle> {
return ElementHandle.from(await this._channel.addScriptTag({ ...options, isPage: this._page!._isPageCall }));
const copy = { ...options };
if (copy.path) {
copy.content = (await fsReadFileAsync(copy.path)).toString();
copy.content += '//# sourceURL=' + copy.path.replace(/\n/g, '');
}
return ElementHandle.from(await this._channel.addScriptTag({ ...copy, isPage: this._page!._isPageCall }));
}
async addStyleTag(options: { url?: string; path?: string; content?: string; }): Promise<ElementHandle> {
const copy = { ...options };
if (copy.path)
copy.content = (await fsReadFileAsync(copy.path)).toString();
return ElementHandle.from(await this._channel.addStyleTag({ ...options, isPage: this._page!._isPageCall }));
}

View file

@ -39,6 +39,11 @@ import { Buffer } from 'buffer';
import { Coverage } from './coverage';
import { Waiter } from './waiter';
import * as fs from 'fs';
import * as util from 'util';
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
export class Page extends ChannelOwner<PageChannel, PageInitializer> {
private _browserContext: BrowserContext;
_ownedContext: BrowserContext | undefined;
@ -494,7 +499,10 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
}
async _pdf(options: types.PDFOptions = {}): Promise<Buffer> {
const path = options.path;
const transportOptions: PDFOptions = { ...options } as PDFOptions;
if (path)
delete (transportOptions as any).path;
if (transportOptions.margin)
transportOptions.margin = { ...transportOptions.margin };
if (typeof options.width === 'number')
@ -507,7 +515,10 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
transportOptions.margin![index] = transportOptions.margin![index] + 'px';
}
const binary = await this._channel.pdf(transportOptions);
return Buffer.from(binary, 'base64');
const buffer = Buffer.from(binary, 'base64');
if (path)
await fsWriteFileAsync(path, buffer);
return buffer;
}
}

50
src/rpc/client/stream.ts Normal file
View file

@ -0,0 +1,50 @@
/**
* 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.
*/
import { Readable } from 'stream';
import { StreamChannel, StreamInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
export class Stream extends ChannelOwner<StreamChannel, StreamInitializer> {
static from(Stream: StreamChannel): Stream {
return (Stream as any)._object;
}
constructor(parent: ChannelOwner, type: string, guid: string, initializer: StreamInitializer) {
super(parent, type, guid, initializer);
}
stream(): Readable {
return new StreamImpl(this._channel);
}
}
class StreamImpl extends Readable {
private _channel: StreamChannel;
constructor(channel: StreamChannel) {
super();
this._channel = channel;
}
async _read(size: number) {
const data = await this._channel.read({ size });
if (data)
this.push(Buffer.from(data, 'base64'));
else
this.push(null);
}
}

View file

@ -15,8 +15,9 @@
*/
import { Download } from '../../download';
import { DownloadChannel, DownloadInitializer } from '../channels';
import { DownloadChannel, DownloadInitializer, StreamChannel } from '../channels';
import { Dispatcher, DispatcherScope } from './dispatcher';
import { StreamDispatcher } from './streamDispatcher';
export class DownloadDispatcher extends Dispatcher<Download, DownloadInitializer> implements DownloadChannel {
constructor(scope: DispatcherScope, download: Download) {
@ -30,6 +31,14 @@ export class DownloadDispatcher extends Dispatcher<Download, DownloadInitializer
return this._object.path();
}
async stream(): Promise<StreamChannel | null> {
const stream = await this._object.createReadStream();
if (!stream)
return null;
await new Promise(f => stream.on('readable', f));
return new StreamDispatcher(this._scope, stream);
}
async failure(): Promise<string | null> {
return this._object.failure();
}

View file

@ -110,12 +110,12 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
await target.setContent(params.html, params);
}
async addScriptTag(params: { url?: string | undefined, path?: string | undefined, content?: string | undefined, type?: string | undefined } & PageAttribution): Promise<ElementHandleChannel> {
async addScriptTag(params: { url?: string, content?: string, type?: string } & PageAttribution): Promise<ElementHandleChannel> {
const target = params.isPage ? this._frame._page : this._frame;
return new ElementHandleDispatcher(this._scope, await target.addScriptTag(params));
}
async addStyleTag(params: { url?: string | undefined, path?: string | undefined, content?: string | undefined } & PageAttribution): Promise<ElementHandleChannel> {
async addStyleTag(params: { url?: string, content?: string } & PageAttribution): Promise<ElementHandleChannel> {
const target = params.isPage ? this._frame._page : this._frame;
return new ElementHandleDispatcher(this._scope, await target.addStyleTag(params));
}

View file

@ -0,0 +1,30 @@
/**
* 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.
*/
import { StreamChannel, StreamInitializer } from '../channels';
import { Dispatcher, DispatcherScope } from './dispatcher';
import * as stream from 'stream';
export class StreamDispatcher extends Dispatcher<stream.Readable, StreamInitializer> implements StreamChannel {
constructor(scope: DispatcherScope, stream: stream.Readable) {
super(scope, stream, 'stream', {});
}
async read(params: { size?: number }): Promise<string> {
const buffer = this._object.read(Math.min(this._object.readableLength, params.size || this._object.readableLength));
return buffer ? buffer.toString('base64') : '';
}
}

View file

@ -162,7 +162,6 @@ describe('Download', function() {
stream.on('data', data => content += data.toString());
await new Promise(f => stream.on('end', f));
expect(content).toBe('Hello world');
stream.close();
await page.close();
});
it('should delete downloads on context destruction', async({browser, server}) => {