chrome-remote-interface
Advanced tools
Comparing version 0.12.3 to 0.13.0
@@ -11,3 +11,3 @@ var events = require('events'); | ||
var notifier = new events.EventEmitter(); | ||
if (callback) { | ||
if (typeof callback === 'function') { | ||
// allow to register the error callback later | ||
@@ -14,0 +14,0 @@ process.nextTick(function () { |
@@ -14,3 +14,3 @@ var defaults = require('./defaults.js'); | ||
self.protocol = options.protocol; | ||
self.fallback = !!(options.fallback); | ||
self.remote = !!(options.remote); | ||
self.chooseTab = options.chooseTab || function () { return 0; }; | ||
@@ -40,3 +40,3 @@ // locals | ||
// return a promise when a callback is not provided | ||
if (callback) { | ||
if (typeof callback === 'function') { | ||
enqueueCommand.call(self, method, params, callback); | ||
@@ -65,3 +65,3 @@ } else { | ||
} | ||
if (callback) { | ||
if (typeof callback === 'function') { | ||
closeWebSocket(callback); | ||
@@ -83,10 +83,23 @@ } else { | ||
function prepareHelp(type, object) { | ||
var help = { | ||
'type': type | ||
}; | ||
function arrayToObject(parameters) { | ||
var keyValue = {}; | ||
parameters.forEach(function (parameter) { | ||
var name = parameter.name; | ||
delete parameter.name; | ||
keyValue[name] = parameter; | ||
}); | ||
return keyValue; | ||
} | ||
function decorate(to, category, object) { | ||
to.category = category; | ||
for (var field in object) { | ||
help[field] = object[field]; | ||
// commands and events have parameters whereas types have properties | ||
if (category === 'type' && field === 'properties' || | ||
field === 'parameters') { | ||
to[field] = arrayToObject(object[field]); | ||
} else { | ||
to[field] = object[field]; | ||
} | ||
} | ||
return help; | ||
} | ||
@@ -96,6 +109,7 @@ | ||
var self = this; | ||
self[domainName][command.name] = function (params, callback) { | ||
var handler = function (params, callback) { | ||
return self.send(domainName + '.' + command.name, params, callback); | ||
}; | ||
self[domainName][command.name].help = prepareHelp('command', command); | ||
decorate(handler, 'command', command); | ||
self[domainName][command.name] = handler; | ||
} | ||
@@ -105,6 +119,7 @@ | ||
var self = this; | ||
self[domainName][event.name] = function (handler) { | ||
var handler = function (handler) { | ||
self.on(domainName + '.' + event.name, handler); | ||
}; | ||
self[domainName][event.name].help = prepareHelp('event', event); | ||
decorate(handler, 'event', event); | ||
self[domainName][event.name] = handler; | ||
} | ||
@@ -114,3 +129,5 @@ | ||
var self = this; | ||
self[domainName][type.id] = type; | ||
var help = {}; | ||
decorate(help, 'type', type); | ||
self[domainName][type.id] = help; | ||
} | ||
@@ -184,8 +201,8 @@ | ||
}; | ||
// if a protocol has been provided then use it otherwise fetch it remotely | ||
// if a protocol has been provided then use it | ||
if (self.protocol) { | ||
continueConnection(); | ||
} else { | ||
// unless the fallback is explicitly requested | ||
options.fallback = self.fallback; | ||
// otherwise user either the local or the remore version | ||
options.remote = self.remote; | ||
devtools.Protocol(options, function (err, protocol) { | ||
@@ -204,3 +221,4 @@ if (err) { | ||
var self = this; | ||
self.ws = new WebSocket(url); | ||
// disable the permessage-deflate as a temporary fix for #39 | ||
self.ws = new WebSocket(url, {'perMessageDeflate': false}); | ||
self.ws.on('open', function () { | ||
@@ -207,0 +225,0 @@ self.notifier.emit('connect', self); |
@@ -8,6 +8,6 @@ var defaults = require('./defaults.js'); | ||
module.exports.Protocol = promisesWrapper(function (options, callback) { | ||
var fallbackProtocol = require('./protocol.json'); | ||
var protocol = {'fallback': true, 'descriptor': fallbackProtocol}; | ||
// if the fallback protocol is explicitly requested | ||
if (options.fallback) { | ||
var localProtocol = require('./protocol.json'); | ||
var protocol = {'remote': false, 'descriptor': localProtocol}; | ||
// if the local protocol is explicitly requested | ||
if (!options.remote) { | ||
callback(null, protocol); | ||
@@ -34,3 +34,3 @@ return; | ||
if (descriptor) { | ||
protocol.fallback = false; | ||
protocol.remote = true; | ||
protocol.descriptor = descriptor; | ||
@@ -119,3 +119,3 @@ } | ||
// just call the function otherwise wrap a promise around its execution | ||
if (callback) { | ||
if (typeof callback === 'function') { | ||
func(options, callback); | ||
@@ -157,30 +157,67 @@ } else { | ||
// callback(protocol) | ||
// XXX this function needs a proper refactor but the inconsistency of the | ||
// fetching process makes it useless for now | ||
function fetchFromChrome(options, info, callback) { | ||
function explodeVersion(v) { | ||
return v.split('.').map(function (x) { | ||
return parseInt(x); | ||
}); | ||
} | ||
// attempt to fetch the protocol directly from the Chromium repository | ||
// according to the current version; fallback to the hardcoded version | ||
// according to the current version | ||
// | ||
// Thanks to Paul Irish. | ||
// (see https://github.com/cyrus-and/chrome-remote-interface/issues/10#issuecomment-146032907) | ||
var version = info['WebKit-Version']; | ||
var match = version.match(/\s\(@(\b[0-9a-f]{5,40}\b)/); | ||
var webKitVersion = info['WebKit-Version']; | ||
var match = webKitVersion.match(/\s\(@(\b[0-9a-f]{5,40}\b)/); | ||
var hash = match[1]; | ||
var fromChromiumDotOrg = (hash <= 202666); | ||
var template = (fromChromiumDotOrg ? | ||
'https://src.chromium.org/blink/trunk/Source/devtools/protocol.json?p=%s': | ||
'https://chromium.googlesource.com/chromium/src/+/%s/third_party/WebKit/Source/devtools/protocol.json?format=TEXT'); | ||
var url = util.format(template, hash); | ||
fetchObject(https, url, function (err, data) { | ||
var descriptor; | ||
if (!err) { | ||
try { | ||
// the file is served base64 encoded from googlesource.com | ||
if (!fromChromiumDotOrg) { | ||
data = new Buffer(data, 'base64').toString(); | ||
var templates; | ||
if (fromChromiumDotOrg) { | ||
templates = ['https://src.chromium.org/blink/trunk/Source/devtools/protocol.json?p=%s']; | ||
} else { | ||
var chromeVersion = explodeVersion(info.Browser.split('/')[1]); | ||
var lastChromeVersion = explodeVersion('53.0.2758.1'); // before the split (https://crbug.com/580337) | ||
// according to https://www.chromium.org/developers/version-numbers | ||
var beforeSplit = (chromeVersion[2] <= lastChromeVersion[2]); // patch not meaningful | ||
templates = (beforeSplit ? | ||
['https://chromium.googlesource.com/chromium/src/+/%s/third_party/WebKit/Source/devtools/protocol.json?format=TEXT'] : | ||
['https://chromium.googlesource.com/chromium/src/+/%s/third_party/WebKit/Source/core/inspector/browser_protocol.json?format=TEXT', | ||
'https://chromium.googlesource.com/chromium/src/+/%s/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json?format=TEXT']); | ||
} | ||
var urls = templates.map(function (template) { | ||
return util.format(template, hash); | ||
}); | ||
var descriptors = []; | ||
urls.forEach(function (url) { | ||
fetchObject(https, url, function (err, data) { | ||
var descriptor; // undefined == fallback | ||
if (!err) { | ||
try { | ||
// the file is served base64 encoded from googlesource.com | ||
if (!fromChromiumDotOrg) { | ||
data = new Buffer(data, 'base64').toString(); | ||
} | ||
descriptor = JSON.parse(data); | ||
} catch (_) { | ||
// fall back | ||
} | ||
descriptor = JSON.parse(data); | ||
} catch (_) { | ||
// fall back | ||
} | ||
} | ||
callback(descriptor); | ||
descriptors.push(descriptor); | ||
if (descriptors.length === urls.length) { | ||
// all must be defined | ||
if (descriptors.indexOf(undefined) !== -1) { | ||
callback(); | ||
return; | ||
} | ||
// merge the domains | ||
descriptors.forEach(function (descriptor, i) { | ||
if (i === 0) { | ||
return; | ||
} | ||
Array.prototype.push.apply(descriptors[0].domains, descriptor.domains); | ||
}); | ||
callback(descriptors[0]); | ||
} | ||
}); | ||
}); | ||
@@ -187,0 +224,0 @@ } |
@@ -12,3 +12,3 @@ { | ||
"homepage": "https://github.com/cyrus-and/chrome-remote-interface", | ||
"version": "0.12.3", | ||
"version": "0.13.0", | ||
"repository": { | ||
@@ -15,0 +15,0 @@ "type": "git", |
117
README.md
@@ -69,14 +69,14 @@ chrome-remote-interface | ||
Using the provided `help` field it's possible to obtain information on the | ||
events and methods available through the [Remote Debugging Protocol][rdb]. For | ||
example to learn how to call `Page.navigate` type: | ||
Every object is *decorated* with the information available through the [Remote | ||
Debugging Protocol][rdb]. The `category` field determines if the member is a | ||
`command`, an `event` or a `type`. Remember that this REPL interface provides | ||
completion. | ||
For example to learn how to call `Page.navigate`: | ||
```javascript | ||
chrome> Page.navigate.help | ||
{ type: 'command', | ||
name: 'navigate', | ||
parameters: | ||
[ { name: 'url', | ||
type: 'string', | ||
description: 'URL to navigate the page to.' } ], | ||
chrome> Page.navigate | ||
{ [Function] | ||
category: 'command', | ||
parameters: { url: { type: 'string', description: 'URL to navigate the page to.' } }, | ||
returns: | ||
@@ -91,12 +91,61 @@ [ { name: 'frameId', | ||
The `type` field determines whether this member is a `command` or an `event`. | ||
To learn about the parameters returned by the `Network.requestWillBeSent` event: | ||
For what concerns the types instead (they usually start with an upper case | ||
letter), just type its name: | ||
```javascript | ||
chrome> Network.requestWillBeSent | ||
{ [Function] | ||
category: 'event', | ||
description: 'Fired when page is about to send HTTP request.', | ||
parameters: | ||
{ requestId: { '$ref': 'RequestId', description: 'Request identifier.' }, | ||
frameId: | ||
{ '$ref': 'Page.FrameId', | ||
description: 'Frame identifier.', | ||
hidden: true }, | ||
loaderId: { '$ref': 'LoaderId', description: 'Loader identifier.' }, | ||
documentURL: | ||
{ type: 'string', | ||
description: 'URL of the document this request is loaded for.' }, | ||
request: { '$ref': 'Request', description: 'Request data.' }, | ||
timestamp: { '$ref': 'Timestamp', description: 'Timestamp.' }, | ||
wallTime: | ||
{ '$ref': 'Timestamp', | ||
hidden: true, | ||
description: 'UTC Timestamp.' }, | ||
initiator: { '$ref': 'Initiator', description: 'Request initiator.' }, | ||
redirectResponse: | ||
{ optional: true, | ||
'$ref': 'Response', | ||
description: 'Redirect response data.' }, | ||
type: | ||
{ '$ref': 'Page.ResourceType', | ||
optional: true, | ||
hidden: true, | ||
description: 'Type of this resource.' } } } | ||
``` | ||
To inspect the `Network.Request` (note that unlike commands and events, types | ||
are named in upper camel case) type: | ||
```javascript | ||
chrome> Network.Timestamp | ||
{ id: 'Timestamp', | ||
type: 'number', | ||
description: 'Number of seconds since epoch.' } | ||
chrome> Network.Request | ||
{ category: 'type', | ||
id: 'Request', | ||
type: 'object', | ||
description: 'HTTP request data.', | ||
properties: | ||
{ url: { type: 'string', description: 'Request URL.' }, | ||
method: { type: 'string', description: 'HTTP request method.' }, | ||
headers: { '$ref': 'Headers', description: 'HTTP request headers.' }, | ||
postData: | ||
{ type: 'string', | ||
optional: true, | ||
description: 'HTTP POST request data.' }, | ||
mixedContentType: | ||
{ optional: true, | ||
type: 'string', | ||
enum: [Object], | ||
description: 'The mixed content status of the request, as defined in http://www.w3.org/TR/mixed-content/' }, | ||
initialPriority: | ||
{ '$ref': 'ResourcePriority', | ||
description: 'Priority of the resource request at the time request is sent.' } } } | ||
``` | ||
@@ -110,3 +159,3 @@ | ||
(see [#10][issue]); rather, that file can be fetched from the proper [source | ||
repository][remote-json] at every connection. By default, the [hardcoded local | ||
repository][remote-json] at every connection. By default, the [local | ||
version][local-json] is used. | ||
@@ -118,4 +167,3 @@ | ||
2. pass a custom protocol descriptor (use `null` to fetch it from the remote | ||
repository) upon | ||
2. pass a custom protocol descriptor upon | ||
[connection](https://github.com/cyrus-and/chrome-remote-interface#moduleoptions-callback); | ||
@@ -143,10 +191,7 @@ | ||
active tab (`function (tabs) { return 0; }`); | ||
- `protocol`: [Remote Debugging Protocol][rdb] descriptor object. Passing `null` | ||
causes the proper protocol descriptor to be fetched from the remote Chrome | ||
repository according to the version exposed by the instrumented Chrome | ||
instance, falling back to the default if that is not possible. Defaults to the | ||
[hardcoded local version][local-json]; | ||
- `fallback`: a boolean indicating whether the protocol must be fetched | ||
*remotely* or if the fallback local version must be used. Defaults to | ||
`false`. | ||
- `protocol`: [Remote Debugging Protocol][rdb] descriptor object. Defaults to | ||
use the protocol chosen according to the `remote` option; | ||
- `remote`: a boolean indicating whether the protocol must be fetched | ||
*remotely* or if the local version must be used. It has not effect if the | ||
`protocol` option is set. Defaults to `false`. | ||
@@ -182,5 +227,3 @@ `callback` is a listener automatically added to the `connect` event of the | ||
Fetch the [Remote Debugging Protocol][rdb] descriptor from the Chrome repository | ||
according to the version of the remote Chrome instance, or fall back to the | ||
local hardcoded version if not available. | ||
Fetch the [Remote Debugging Protocol][rdb] descriptor. | ||
@@ -191,5 +234,5 @@ `options` is an object with the following optional properties: | ||
- `port`: [Remote Debugging Protocol][rdb] port. Defaults to `9222`; | ||
- `fallback`: a boolean indicating whether the protocol must be fetched | ||
*remotely* or if the fallback local version must be returned. Defaults to | ||
`false`. | ||
- `remote`: a boolean indicating whether the protocol must be fetched | ||
*remotely* or if the local version must be returned. If it is not possible to | ||
fulfill the request then the local version is used. Defaults to `false`. | ||
@@ -201,4 +244,4 @@ `callback` is executed when the protocol is fetched, it gets the following | ||
- `protocol`: an object with the following properties: | ||
- `fallback`: a boolean indicating whether the returned descriptor is the | ||
hardcoded version (due to user choice or error) or not; | ||
- `remote`: a boolean indicating whether the returned descriptor is the | ||
remote version or not (due to user choice or error); | ||
- `descriptor`: the [Remote Debugging Protocol][rdb] descriptor. | ||
@@ -522,3 +565,3 @@ | ||
[local-json]: lib/protocol.json | ||
[remote-json]: https://chromium.googlesource.com/chromium/blink/+/master/Source/devtools/protocol.json | ||
[remote-json]: https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/Source/ | ||
[issue]: https://github.com/cyrus-and/chrome-remote-interface/issues/10 |
@@ -9,6 +9,6 @@ var Chrome = require('../'); | ||
describe('with callback', function () { | ||
it('should return the protocol descriptor from Chrome', function (done) { | ||
it('should return the local protocol descriptor', function (done) { | ||
Chrome.Protocol(function (err, protocol) { | ||
assert.ifError(err); | ||
assert(!protocol.fallback); | ||
assert(!protocol.remote); | ||
assert.equal(typeof protocol.descriptor, 'object'); | ||
@@ -19,6 +19,6 @@ assert.equal(typeof protocol.descriptor.version, 'object'); | ||
}); | ||
it('should return the hardcoded protocol descriptor (on error)', function (done) { | ||
Chrome.Protocol({'port':1}, function (err, protocol) { | ||
it('should return the local protocol descriptor (on error)', function (done) { | ||
Chrome.Protocol({'remote': true, 'port':1}, function (err, protocol) { | ||
assert.ifError(err); | ||
assert(protocol.fallback); | ||
assert(!protocol.remote); | ||
assert.equal(typeof protocol.descriptor, 'object'); | ||
@@ -29,6 +29,6 @@ assert.equal(typeof protocol.descriptor.version, 'object'); | ||
}); | ||
it('should return the hardcoded protocol descriptor (if requested)', function (done) { | ||
Chrome.Protocol({'fallback': true}, function (err, protocol) { | ||
it('should return the remote protocol descriptor', function (done) { | ||
Chrome.Protocol({'remote': true}, function (err, protocol) { | ||
assert.ifError(err); | ||
assert(protocol.fallback); | ||
assert(protocol.remote); | ||
assert.equal(typeof protocol.descriptor, 'object'); | ||
@@ -41,5 +41,5 @@ assert.equal(typeof protocol.descriptor.version, 'object'); | ||
describe('without callback', function () { | ||
it('should return the protocol descriptor from Chrome', function (done) { | ||
it('should return the local protocol descriptor', function (done) { | ||
Chrome.Protocol().then(function (protocol) { | ||
assert(!protocol.fallback); | ||
assert(!protocol.remote); | ||
assert.equal(typeof protocol.descriptor, 'object'); | ||
@@ -52,5 +52,5 @@ assert.equal(typeof protocol.descriptor.version, 'object'); | ||
}); | ||
it('should return the hardcoded protocol descriptor (on error)', function (done) { | ||
Chrome.Protocol({'port':1}).then(function (protocol) { | ||
assert(protocol.fallback); | ||
it('should return the local protocol descriptor (on error)', function (done) { | ||
Chrome.Protocol({'remote': true, 'port':1}).then(function (protocol) { | ||
assert(!protocol.remote); | ||
assert.equal(typeof protocol.descriptor, 'object'); | ||
@@ -63,5 +63,5 @@ assert.equal(typeof protocol.descriptor.version, 'object'); | ||
}); | ||
it('should return the hardcoded protocol descriptor (if requested)', function (done) { | ||
Chrome.Protocol({'fallback': true}).then(function (protocol) { | ||
assert(protocol.fallback); | ||
it('should return the remote protocol descriptor', function (done) { | ||
Chrome.Protocol({'remote': true}).then(function (protocol) { | ||
assert(protocol.remote); | ||
assert.equal(typeof protocol.descriptor, 'object'); | ||
@@ -68,0 +68,0 @@ assert.equal(typeof protocol.descriptor.version, 'object'); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
590175
13476
559