Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[refactor] Execution Context #15

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ReadMe.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Puppeteer-IE

Headless **Internet Explorer** NodeJS API inspired by [Puppeteer](https://pptr.dev/).
NodeJS API for headless **Internet Explorer** inspired by [Puppeteer](https://pptr.dev/).

**[ Notice ]** [Microsoft Edge](https://www.microsoft.com/en-us/windows/microsoft-edge) isn't supported by this package as it utilizes [ActiveX](https://msdn.microsoft.com/en-us/library/windows/desktop/ms693753),
whereas Edge uses the [WebDriver protocol](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/) & [DevTools Protocol](https://docs.microsoft.com/en-us/microsoft-edge/devtools-protocol/) for automation.
Expand Down Expand Up @@ -33,7 +33,7 @@ Only change the Package Name, and then do as [Puppeteer does](https://pptr.dev/#

**[ Recommendation ]** Use [DayDream](https://github.com/segmentio/daydream) to record operation scripts in [Google Chrome](https://www.google.com/chrome/).

**API document** accesses from https://techquery.github.io/Puppeteer-IE/, `npm docs` or `npm run help`.
**API document** accesses from https://tech-query.me/Puppeteer-IE/, `npm docs` or `npm run help`.



Expand Down
3,083 changes: 2,330 additions & 753 deletions package-lock.json

Large diffs are not rendered by default.

26 changes: 14 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"name": "puppeteer-ie",
"version": "0.5.7",
"descripton": "Headless Internet Explorer NodeJS API inspired by Puppeteer.",
"version": "0.6.0",
"descripton": "NodeJS API for headless Internet Explorer inspired by Puppeteer",
"keywords": [
"internet-explorer",
"headless-browsers",
"activex-control",
"puppeteer"
],
"author": "shiy007@qq.com",
"author": "shiy2008@gmail.com",
"license": "LGPL-3.0",
"homepage": "https://techquery.github.io/Puppeteer-IE/",
"homepage": "https://tech-query.me/Puppeteer-IE/",
"repository": {
"type": "git",
"url": "git+https://github.com/TechQuery/Puppeteer-IE.git"
Expand All @@ -29,7 +29,7 @@
"lint": "eslint ./source/ ./test/ --fix",
"format": "prettier --write \"{,!(node_modules|.git|source|test)/**/}*.html\"",
"document": "jsdoc ./source/ -c .jsdoc.json && npm run format",
"check": "mocha -r should --recursive --no-timeouts -c --inline-diffs",
"check": "npm run document && mocha -r should --recursive --no-timeouts -c --inline-diffs",
"test": "npm run check -- --exit",
"debug": "npm run check -- --inspect-brk",
"build": "npm run lint && npm run document",
Expand All @@ -42,22 +42,24 @@
}
},
"dependencies": {
"@babel/core": "^7.3.4",
"@babel/polyfill": "^7.2.5",
"@babel/runtime": "^7.2.0",
"@tech_query/node-toolkit": "^0.8.2",
"@babel/preset-env": "^7.3.4",
"@babel/runtime": "^7.3.4",
"@tech_query/node-toolkit": "^0.9.3",
"cookie": "^0.3.1",
"fs-extra": "^7.0.1",
"html2canvas": "^0.5.0-beta4",
"winax": "^1.0.16"
"winax": "^1.0.17"
},
"devDependencies": {
"docdash": "^1.0.1",
"eslint": "^5.11.1",
"docdash": "^1.0.3",
"eslint": "^5.15.1",
"husky": "^1.3.1",
"jsdoc": "^3.5.5",
"jsdoc-inheritance-diagram": "^1.2.3",
"koapache": "^1.0.4",
"mocha": "^5.2.0",
"koapache": "^1.0.6",
"mocha": "^6.0.2",
"should": "^13.2.3"
}
}
23 changes: 2 additions & 21 deletions source/BrowserService.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,13 @@

function Puppeteer() {

this.queue = [ ], this.stack = { };

setInterval( this.sendMessage.bind( this ) );
this.stack = { };
}

var slice = Array.prototype.slice;

Puppeteer.prototype = {
constructor: Puppeteer,
sendMessage: function () {

if (self.name || (! this.queue[0])) return;

var message = this.queue.shift();

self.name = [
'B',
message.type,
message.key || '',
JSON.stringify( message.data ) || ''
].join('_');
},
sendData: function (key, data) {

if (arguments.length < 2) data = key, key = '';
Expand All @@ -47,11 +32,7 @@
else if (data instanceof Element)
data = data.sourceIndex;

this.queue.push({
type: type,
data: data,
key: key
});
self.postMessage([type, key || '', data || ''], '*');
},
execute: function (key, code, parameter) {

Expand Down
63 changes: 28 additions & 35 deletions source/ExecutionContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ const { readFileSync } = require('fs'), { join } = require('path');

const { currentModulePath, toES_5 } = require('@tech_query/node-toolkit');

const { waitFor } = require('./utility');


const BrowserService = readFileSync(
join(currentModulePath(), '../BrowserService.js')
Expand All @@ -32,9 +30,20 @@ class ExecutionContext {
this._page = page, this._pending = { }, this._export = { };
}

async require(module, file, namespace) {
require(module, file, namespace) {

const window = this._page.window;
const { window } = this._page;

const ready = new Promise(resolve => {

function end({ data }) {

if (data === true)
window.detachEvent('onmessage', end), resolve();
}

setTimeout(() => window.attachEvent('onmessage', end));
});

window.execScript(
readFileSync(
Expand All @@ -44,24 +53,22 @@ class ExecutionContext {

window.execScript(`setTimeout(function check() {

(self.name = (self.${namespace || module} instanceof Object)) ||
if (self.${namespace || module} instanceof Object)
self.postMessage(true, '*');
else
setTimeout( check );
})`);

await waitFor(() => (window.name === 'true'));

window.name = '';
return ready;
}

async attach() {

await this.require('@babel/polyfill', 'polyfill', 'Promise');

if (this._interval != null) clearInterval( this._interval );

this._page.window.execScript( BrowserService );

this._interval = setInterval( this.readMessage.bind( this ) );
this._page.window.attachEvent('onmessage', this.readMessage.bind( this ));

for (let name in this._export)
this.expose(name, this._export[ name ]);
Expand All @@ -77,46 +84,32 @@ class ExecutionContext {
return error;
}

async readMessage() {

const window = this._page.window;

var data = /B_(\w)_(\d*)_([\s\S]*)/.exec( window.name );

if (! data) return;

window.name = '';

const promise = this._pending[ data[2] ];

if ( data[3] ) try {

data[3] = JSON.parse( data[3] );
async readMessage({ data: [type, key, data] }) {

} catch (error) { console.error( error ); }
const [resolve, reject] = this._pending[ key ] || [ ];

switch ( data[1] ) {
switch ( type ) {
case 'R':
if ( promise ) promise[0]( data[3] );
if ( resolve ) resolve( data );
break;
case 'E': {
let error = ExecutionContext.errorOf( data[3] );
let error = ExecutionContext.errorOf( data );

if ( promise )
promise[1]( error );
if ( reject )
reject( error );
else
this._page.emit('pageerror', error);

break;
}
case 'M':
if (data[3].source === 'console')
if (data.source === 'console')
this._page.emit(
'console', new ConsoleMessage(data[3].type, data[3].data)
'console', new ConsoleMessage(data.type, data.data)
);
break;
case 'C':
await this.execute(data[2], data[3]);
await this.execute(key, data);
}
}

Expand Down
32 changes: 12 additions & 20 deletions source/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,26 +276,6 @@ class Page extends EventEmitter {
*/
deleteCookie(...cookies) { return this.pushCookie(cookies, true); }

/**
* Gets the full HTML contents of the page, including the doctype.
*
* @return {Promise<string>}
*/
async content() {

const DocType = this.document.doctype;

var type = `<!DocType ${(DocType.name + '').toUpperCase()}`;

if ( DocType.publicId.valueOf() )
type += ` Public "${DocType.publicId}"`;

if ( DocType.systemId.valueOf() )
type += ` "${DocType.systemId}"`;

return `${type}>${this.document.documentElement.outerHTML}`;
}

/**
* @param {string} HTML - HTML markup to assign to the page
*/
Expand Down Expand Up @@ -473,6 +453,18 @@ class Page extends EventEmitter {
}`](condition, options || { }, ...parameter);
}

/**
* Gets the full HTML contents of the page, including the doctype.
*
* @return {Promise<string>}
*/
content() {

return this.evaluate(
() => ((new XMLSerializer()).serializeToString( document ))
);
}

/**
* The method adds a function called `name` on the page's window object.
*
Expand Down
18 changes: 9 additions & 9 deletions source/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class Puppeteer {
*
* @return {Promise<Browser>}
*/
static async launch({headless = true} = {}) {
static async launch({headless = true} = { }) {

return stack[stack.push(new Browser( headless )) - 1];
}
Expand All @@ -64,25 +64,25 @@ class Puppeteer {

return page && (page._target.FullName + '');
}
}


async function clear(error) {
/**
* @param {?Error} error
*/
static async exit(error) {

await Promise.all( stack.map(browser => browser.close()) );
await Promise.all( stack.map(browser => browser.close()) );

if (error instanceof Error) {
if (!(error instanceof Error)) process.exit(0);

console.error( error );

process.exit(1);
}

process.exit(0);
}


for (let event of ['uncaughtException', 'unhandledRejection', 'SIGINT', 'exit'])
process.on(event, clear);
process.on(event, Puppeteer.exit);


module.exports = Puppeteer;