opal 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +17 -0
- data/CHANGELOG.md +35 -1
- data/Gemfile +1 -0
- data/HACKING.md +47 -26
- data/benchmark/benchmarks +415 -103
- data/benchmark/bm_call_overhead.yml +28 -0
- data/benchmark/run.rb +61 -40
- data/docs/cdp_common.json +3364 -0
- data/docs/cdp_common.md +18 -0
- data/docs/{headless_chrome.md → headless_browsers.md} +31 -12
- data/lib/opal/ast/builder.rb +1 -1
- data/lib/opal/builder.rb +6 -1
- data/lib/opal/builder_processors.rb +5 -3
- data/lib/opal/cache.rb +1 -7
- data/lib/opal/cli_options.rb +72 -58
- data/lib/opal/cli_runners/chrome.rb +47 -9
- data/lib/opal/cli_runners/chrome_cdp_interface.rb +238 -112
- data/lib/opal/cli_runners/compiler.rb +146 -13
- data/lib/opal/cli_runners/deno.rb +32 -0
- data/lib/opal/cli_runners/firefox.rb +350 -0
- data/lib/opal/cli_runners/firefox_cdp_interface.rb +212 -0
- data/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface.cmd +17 -0
- data/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface.ps1 +28 -0
- data/lib/opal/cli_runners/node_modules/.package-lock.json +41 -0
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/LICENSE +1 -1
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/README.md +322 -182
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/bin/client.js +99 -114
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/chrome-remote-interface.js +1 -11
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/index.js +16 -11
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/api.js +41 -33
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/chrome.js +224 -214
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/devtools.js +71 -191
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/external-request.js +26 -6
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/protocol.json +20788 -9049
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/websocket-wrapper.js +10 -3
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/package.json +59 -123
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/webpack.config.js +25 -32
- data/lib/opal/cli_runners/node_modules/commander/History.md +298 -0
- data/lib/opal/cli_runners/node_modules/commander/LICENSE +22 -0
- data/lib/opal/cli_runners/node_modules/commander/Readme.md +217 -61
- data/lib/opal/cli_runners/node_modules/commander/index.js +431 -145
- data/lib/opal/cli_runners/node_modules/commander/package.json +16 -79
- data/lib/opal/cli_runners/node_modules/ws/README.md +334 -98
- data/lib/opal/cli_runners/node_modules/ws/browser.js +8 -0
- data/lib/opal/cli_runners/node_modules/ws/index.js +5 -10
- data/lib/opal/cli_runners/node_modules/ws/lib/buffer-util.js +129 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/constants.js +10 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/event-target.js +184 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/extension.js +223 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/limiter.js +55 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/permessage-deflate.js +518 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/receiver.js +607 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/sender.js +409 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/stream.js +180 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/validation.js +104 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/websocket-server.js +447 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/websocket.js +1195 -0
- data/lib/opal/cli_runners/node_modules/ws/package.json +40 -106
- data/lib/opal/cli_runners/package-lock.json +62 -0
- data/lib/opal/cli_runners/package.json +1 -1
- data/lib/opal/cli_runners.rb +26 -4
- data/lib/opal/nodes/args/prepare_post_args.rb +2 -2
- data/lib/opal/nodes/def.rb +8 -8
- data/lib/opal/nodes/iter.rb +12 -12
- data/lib/opal/nodes/logic.rb +1 -1
- data/lib/opal/nodes/masgn.rb +2 -2
- data/lib/opal/parser/with_ruby_lexer.rb +1 -1
- data/lib/opal/paths.rb +14 -0
- data/lib/opal/rewriter.rb +2 -0
- data/lib/opal/rewriters/forward_args.rb +52 -4
- data/lib/opal/rewriters/targeted_patches.rb +94 -0
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/basic_object.rb +1 -1
- data/opal/corelib/boolean.rb +2 -2
- data/opal/corelib/class.rb +11 -0
- data/opal/corelib/constants.rb +3 -3
- data/opal/corelib/enumerable.rb +4 -0
- data/opal/corelib/enumerator.rb +1 -1
- data/opal/corelib/hash.rb +2 -2
- data/opal/corelib/helpers.rb +1 -1
- data/opal/corelib/kernel.rb +3 -3
- data/opal/corelib/method.rb +1 -1
- data/opal/corelib/module.rb +29 -8
- data/opal/corelib/proc.rb +7 -5
- data/opal/corelib/runtime.js +141 -78
- data/opal/corelib/set.rb +252 -0
- data/opal/corelib/string.rb +2 -1
- data/opal/corelib/time.rb +2 -2
- data/opal/opal.rb +1 -0
- data/opal.gemspec +1 -0
- data/spec/filters/bugs/array.rb +22 -13
- data/spec/filters/bugs/base64.rb +5 -5
- data/spec/filters/bugs/basicobject.rb +16 -8
- data/spec/filters/bugs/bigdecimal.rb +161 -160
- data/spec/filters/bugs/binding.rb +10 -10
- data/spec/filters/bugs/class.rb +8 -8
- data/spec/filters/bugs/complex.rb +2 -1
- data/spec/filters/bugs/date.rb +79 -81
- data/spec/filters/bugs/datetime.rb +29 -29
- data/spec/filters/bugs/delegate.rb +1 -3
- data/spec/filters/bugs/encoding.rb +69 -69
- data/spec/filters/bugs/enumerable.rb +22 -20
- data/spec/filters/bugs/enumerator.rb +88 -85
- data/spec/filters/bugs/exception.rb +46 -40
- data/spec/filters/bugs/file.rb +32 -32
- data/spec/filters/bugs/float.rb +26 -21
- data/spec/filters/bugs/freeze.rb +88 -0
- data/spec/filters/bugs/hash.rb +39 -38
- data/spec/filters/bugs/integer.rb +57 -44
- data/spec/filters/bugs/io.rb +1 -1
- data/spec/filters/bugs/kernel.rb +349 -269
- data/spec/filters/bugs/language.rb +220 -188
- data/spec/filters/bugs/main.rb +5 -3
- data/spec/filters/bugs/marshal.rb +38 -38
- data/spec/filters/bugs/math.rb +2 -1
- data/spec/filters/bugs/method.rb +73 -62
- data/spec/filters/bugs/module.rb +163 -143
- data/spec/filters/bugs/numeric.rb +6 -6
- data/spec/filters/bugs/objectspace.rb +16 -16
- data/spec/filters/bugs/openstruct.rb +1 -1
- data/spec/filters/bugs/pack_unpack.rb +51 -51
- data/spec/filters/bugs/pathname.rb +7 -7
- data/spec/filters/bugs/proc.rb +63 -63
- data/spec/filters/bugs/random.rb +7 -6
- data/spec/filters/bugs/range.rb +12 -9
- data/spec/filters/bugs/rational.rb +8 -7
- data/spec/filters/bugs/regexp.rb +49 -48
- data/spec/filters/bugs/ruby-32.rb +56 -0
- data/spec/filters/bugs/set.rb +30 -30
- data/spec/filters/bugs/singleton.rb +4 -4
- data/spec/filters/bugs/string.rb +187 -99
- data/spec/filters/bugs/stringio.rb +7 -0
- data/spec/filters/bugs/stringscanner.rb +68 -68
- data/spec/filters/bugs/struct.rb +11 -9
- data/spec/filters/bugs/symbol.rb +1 -1
- data/spec/filters/bugs/time.rb +78 -63
- data/spec/filters/bugs/trace_point.rb +4 -4
- data/spec/filters/bugs/unboundmethod.rb +32 -17
- data/spec/filters/bugs/warnings.rb +8 -12
- data/spec/filters/unsupported/array.rb +24 -107
- data/spec/filters/unsupported/basicobject.rb +12 -12
- data/spec/filters/unsupported/bignum.rb +27 -52
- data/spec/filters/unsupported/class.rb +1 -2
- data/spec/filters/unsupported/delegator.rb +3 -3
- data/spec/filters/unsupported/enumerable.rb +2 -9
- data/spec/filters/unsupported/enumerator.rb +2 -11
- data/spec/filters/unsupported/file.rb +1 -1
- data/spec/filters/unsupported/float.rb +28 -47
- data/spec/filters/unsupported/hash.rb +8 -14
- data/spec/filters/unsupported/integer.rb +75 -91
- data/spec/filters/unsupported/kernel.rb +17 -35
- data/spec/filters/unsupported/language.rb +11 -19
- data/spec/filters/unsupported/marshal.rb +22 -41
- data/spec/filters/unsupported/matchdata.rb +28 -52
- data/spec/filters/unsupported/math.rb +1 -1
- data/spec/filters/unsupported/privacy.rb +229 -285
- data/spec/filters/unsupported/range.rb +1 -5
- data/spec/filters/unsupported/regexp.rb +40 -66
- data/spec/filters/unsupported/set.rb +2 -2
- data/spec/filters/unsupported/singleton.rb +4 -4
- data/spec/filters/unsupported/string.rb +305 -508
- data/spec/filters/unsupported/struct.rb +3 -4
- data/spec/filters/unsupported/symbol.rb +15 -18
- data/spec/filters/unsupported/thread.rb +1 -7
- data/spec/filters/unsupported/time.rb +159 -202
- data/spec/filters/unsupported/usage_of_files.rb +170 -259
- data/spec/lib/builder_spec.rb +4 -4
- data/spec/lib/rewriters/forward_args_spec.rb +32 -12
- data/spec/mspec-opal/runner.rb +2 -0
- data/spec/ruby_specs +4 -0
- data/stdlib/deno/base.rb +28 -0
- data/stdlib/deno/file.rb +340 -0
- data/stdlib/{headless_chrome.rb → headless_browser/base.rb} +1 -1
- data/stdlib/headless_browser/file.rb +15 -0
- data/stdlib/headless_browser.rb +4 -0
- data/stdlib/native.rb +1 -1
- data/stdlib/nodejs/file.rb +5 -0
- data/stdlib/opal/platform.rb +8 -6
- data/stdlib/opal-platform.rb +14 -8
- data/stdlib/set.rb +1 -258
- data/tasks/benchmarking.rake +62 -19
- data/tasks/performance.rake +1 -1
- data/tasks/testing.rake +5 -3
- data/test/nodejs/test_file.rb +29 -10
- data/test/opal/http_server.rb +28 -11
- data/test/opal/unsupported_and_bugs.rb +2 -1
- metadata +89 -50
- data/lib/opal/cli_runners/node_modules/ultron/LICENSE +0 -22
- data/lib/opal/cli_runners/node_modules/ultron/index.js +0 -138
- data/lib/opal/cli_runners/node_modules/ultron/package.json +0 -112
- data/lib/opal/cli_runners/node_modules/ws/SECURITY.md +0 -33
- data/lib/opal/cli_runners/node_modules/ws/lib/BufferUtil.fallback.js +0 -56
- data/lib/opal/cli_runners/node_modules/ws/lib/BufferUtil.js +0 -15
- data/lib/opal/cli_runners/node_modules/ws/lib/ErrorCodes.js +0 -28
- data/lib/opal/cli_runners/node_modules/ws/lib/EventTarget.js +0 -158
- data/lib/opal/cli_runners/node_modules/ws/lib/Extensions.js +0 -69
- data/lib/opal/cli_runners/node_modules/ws/lib/PerMessageDeflate.js +0 -339
- data/lib/opal/cli_runners/node_modules/ws/lib/Receiver.js +0 -520
- data/lib/opal/cli_runners/node_modules/ws/lib/Sender.js +0 -438
- data/lib/opal/cli_runners/node_modules/ws/lib/Validation.fallback.js +0 -9
- data/lib/opal/cli_runners/node_modules/ws/lib/Validation.js +0 -17
- data/lib/opal/cli_runners/node_modules/ws/lib/WebSocket.js +0 -705
- data/lib/opal/cli_runners/node_modules/ws/lib/WebSocketServer.js +0 -336
- data/spec/filters/bugs/boolean.rb +0 -3
- data/spec/filters/bugs/matrix.rb +0 -3
- data/spec/filters/unsupported/fixnum.rb +0 -15
- data/spec/filters/unsupported/freeze.rb +0 -102
- data/spec/filters/unsupported/pathname.rb +0 -4
- data/spec/filters/unsupported/proc.rb +0 -4
- data/spec/filters/unsupported/random.rb +0 -5
- data/spec/filters/unsupported/taint.rb +0 -162
@@ -2,17 +2,25 @@
|
|
2
2
|
|
3
3
|
const EventEmitter = require('events');
|
4
4
|
const util = require('util');
|
5
|
+
const formatUrl = require('url').format;
|
6
|
+
const parseUrl = require('url').parse;
|
5
7
|
|
6
8
|
const WebSocket = require('ws');
|
7
9
|
|
8
|
-
const api = require('./api');
|
9
|
-
const defaults = require('./defaults');
|
10
|
-
const devtools = require('./devtools');
|
10
|
+
const api = require('./api.js');
|
11
|
+
const defaults = require('./defaults.js');
|
12
|
+
const devtools = require('./devtools.js');
|
11
13
|
|
12
14
|
class ProtocolError extends Error {
|
13
|
-
constructor(response) {
|
14
|
-
|
15
|
-
|
15
|
+
constructor(request, response) {
|
16
|
+
let {message} = response;
|
17
|
+
if (response.data) {
|
18
|
+
message += ` (${response.data})`;
|
19
|
+
}
|
20
|
+
super(message);
|
21
|
+
// attach the original response as well
|
22
|
+
this.request = request;
|
23
|
+
this.response = response;
|
16
24
|
}
|
17
25
|
}
|
18
26
|
|
@@ -20,9 +28,9 @@ class Chrome extends EventEmitter {
|
|
20
28
|
constructor(options, notifier) {
|
21
29
|
super();
|
22
30
|
// options
|
23
|
-
const defaultTarget =
|
24
|
-
// prefer type = 'page'
|
25
|
-
// browser tabs (fall back to the first
|
31
|
+
const defaultTarget = (targets) => {
|
32
|
+
// prefer type = 'page' inspectable targets as they represents
|
33
|
+
// browser tabs (fall back to the first inspectable target
|
26
34
|
// otherwise)
|
27
35
|
let backup;
|
28
36
|
let target = targets.find((target) => {
|
@@ -44,245 +52,247 @@ class Chrome extends EventEmitter {
|
|
44
52
|
this.host = options.host || defaults.HOST;
|
45
53
|
this.port = options.port || defaults.PORT;
|
46
54
|
this.secure = !!(options.secure);
|
55
|
+
this.useHostName = !!(options.useHostName);
|
56
|
+
this.alterPath = options.alterPath || ((path) => path);
|
47
57
|
this.protocol = options.protocol;
|
48
|
-
this.
|
49
|
-
this.target = options.target ||
|
50
|
-
/* backward compatibility */ options.tab || options.chooseTab
|
51
|
-
|| defaultTarget;
|
58
|
+
this.local = !!(options.local);
|
59
|
+
this.target = options.target || defaultTarget;
|
52
60
|
// locals
|
53
|
-
EventEmitter.call(this);
|
54
61
|
this._notifier = notifier;
|
55
62
|
this._callbacks = {};
|
56
63
|
this._nextCommandId = 1;
|
64
|
+
// properties
|
65
|
+
this.webSocketUrl = undefined;
|
57
66
|
// operations
|
58
|
-
|
67
|
+
this._start();
|
59
68
|
}
|
60
|
-
}
|
61
|
-
|
62
|
-
// avoid misinterpreting protocol's members as custom util.inspect functions
|
63
|
-
Chrome.prototype.inspect = function (depth, options) {
|
64
|
-
options.customInspect = false;
|
65
|
-
return util.inspect(this, options);
|
66
|
-
};
|
67
69
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
params = undefined;
|
70
|
+
// avoid misinterpreting protocol's members as custom util.inspect functions
|
71
|
+
inspect(depth, options) {
|
72
|
+
options.customInspect = false;
|
73
|
+
return util.inspect(this, options);
|
73
74
|
}
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
75
|
+
|
76
|
+
send(method, params, sessionId, callback) {
|
77
|
+
// handle optional arguments
|
78
|
+
const optionals = Array.from(arguments).slice(1);
|
79
|
+
params = optionals.find(x => typeof x === 'object');
|
80
|
+
sessionId = optionals.find(x => typeof x === 'string');
|
81
|
+
callback = optionals.find(x => typeof x === 'function');
|
82
|
+
// return a promise when a callback is not provided
|
83
|
+
if (typeof callback === 'function') {
|
84
|
+
this._enqueueCommand(method, params, sessionId, callback);
|
85
|
+
return undefined;
|
86
|
+
} else {
|
87
|
+
return new Promise((fulfill, reject) => {
|
88
|
+
this._enqueueCommand(method, params, sessionId, (error, response) => {
|
89
|
+
if (error) {
|
90
|
+
const request = {method, params, sessionId};
|
91
|
+
reject(
|
92
|
+
error instanceof Error
|
93
|
+
? error // low-level WebSocket error
|
94
|
+
: new ProtocolError(request, response)
|
95
|
+
);
|
96
|
+
} else {
|
97
|
+
fulfill(response);
|
98
|
+
}
|
99
|
+
});
|
85
100
|
});
|
86
|
-
}
|
101
|
+
}
|
87
102
|
}
|
88
|
-
};
|
89
103
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
close(callback) {
|
105
|
+
const closeWebSocket = (callback) => {
|
106
|
+
// don't close if it's already closed
|
107
|
+
if (this._ws.readyState === 3) {
|
108
|
+
callback();
|
109
|
+
} else {
|
110
|
+
// don't notify on user-initiated shutdown ('disconnect' event)
|
111
|
+
this._ws.removeAllListeners('close');
|
112
|
+
this._ws.once('close', () => {
|
113
|
+
this._ws.removeAllListeners();
|
114
|
+
callback();
|
115
|
+
});
|
116
|
+
this._ws.close();
|
117
|
+
}
|
118
|
+
};
|
119
|
+
if (typeof callback === 'function') {
|
120
|
+
closeWebSocket(callback);
|
121
|
+
return undefined;
|
122
|
+
} else {
|
123
|
+
return new Promise((fulfill, reject) => {
|
124
|
+
closeWebSocket(fulfill);
|
125
|
+
});
|
126
|
+
}
|
107
127
|
}
|
108
|
-
};
|
109
128
|
|
110
|
-
//
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
}
|
144
|
-
|
145
|
-
// fetch the protocol according to 'protocol' and 'remote'
|
146
|
-
function fetchProtocol(options) {
|
147
|
-
const chrome = this;
|
148
|
-
return new Promise(function (fulfill, reject) {
|
149
|
-
// if a protocol has been provided then use it
|
150
|
-
if (chrome.protocol) {
|
151
|
-
fulfill(chrome.protocol);
|
152
|
-
}
|
153
|
-
// otherwise user either the local or the remote version
|
154
|
-
else {
|
155
|
-
options.remote = chrome.remote;
|
156
|
-
devtools.Protocol(options).then(function (protocol) {
|
157
|
-
fulfill(protocol.descriptor);
|
158
|
-
}).catch(reject);
|
129
|
+
// initiate the connection process
|
130
|
+
async _start() {
|
131
|
+
const options = {
|
132
|
+
host: this.host,
|
133
|
+
port: this.port,
|
134
|
+
secure: this.secure,
|
135
|
+
useHostName: this.useHostName,
|
136
|
+
alterPath: this.alterPath
|
137
|
+
};
|
138
|
+
try {
|
139
|
+
// fetch the WebSocket debugger URL
|
140
|
+
const url = await this._fetchDebuggerURL(options);
|
141
|
+
// allow the user to alter the URL
|
142
|
+
const urlObject = parseUrl(url);
|
143
|
+
urlObject.pathname = options.alterPath(urlObject.pathname);
|
144
|
+
this.webSocketUrl = formatUrl(urlObject);
|
145
|
+
// update the connection parameters using the debugging URL
|
146
|
+
options.host = urlObject.hostname;
|
147
|
+
options.port = urlObject.port || options.port;
|
148
|
+
// fetch the protocol and prepare the API
|
149
|
+
const protocol = await this._fetchProtocol(options);
|
150
|
+
api.prepare(this, protocol);
|
151
|
+
// finally connect to the WebSocket
|
152
|
+
await this._connectToWebSocket();
|
153
|
+
// since the handler is executed synchronously, the emit() must be
|
154
|
+
// performed in the next tick so that uncaught errors in the client code
|
155
|
+
// are not intercepted by the Promise mechanism and therefore reported
|
156
|
+
// via the 'error' event
|
157
|
+
process.nextTick(() => {
|
158
|
+
this._notifier.emit('connect', this);
|
159
|
+
});
|
160
|
+
} catch (err) {
|
161
|
+
this._notifier.emit('error', err);
|
159
162
|
}
|
160
|
-
});
|
161
|
-
}
|
162
|
-
|
163
|
-
// extract the debugger URL from a target-like object
|
164
|
-
function fetchFromObject(fulfill, reject, target) {
|
165
|
-
const url = (target || {}).webSocketDebuggerUrl;
|
166
|
-
if (url) {
|
167
|
-
fulfill(url);
|
168
|
-
} else {
|
169
|
-
const targetStr = JSON.stringify(target, null, 4);
|
170
|
-
const err = new Error('Invalid target ' + targetStr);
|
171
|
-
reject(err);
|
172
163
|
}
|
173
|
-
}
|
174
164
|
|
175
|
-
// fetch the WebSocket URL according to 'target'
|
176
|
-
|
177
|
-
|
178
|
-
return new Promise(function (fulfill, reject) {
|
179
|
-
// note: when DevTools are open or another WebSocket is connected to a
|
180
|
-
// given target the 'webSocketDebuggerUrl' field is not available
|
181
|
-
let userTarget = chrome.target;
|
165
|
+
// fetch the WebSocket URL according to 'target'
|
166
|
+
async _fetchDebuggerURL(options) {
|
167
|
+
const userTarget = this.target;
|
182
168
|
switch (typeof userTarget) {
|
183
|
-
case 'string':
|
169
|
+
case 'string': {
|
170
|
+
let idOrUrl = userTarget;
|
184
171
|
// use default host and port if omitted (and a relative URL is specified)
|
185
|
-
if (
|
186
|
-
|
187
|
-
userTarget = prefix + userTarget;
|
172
|
+
if (idOrUrl.startsWith('/')) {
|
173
|
+
idOrUrl = `ws://${this.host}:${this.port}${idOrUrl}`;
|
188
174
|
}
|
189
175
|
// a WebSocket URL is specified by the user (e.g., node-inspector)
|
190
|
-
if (
|
191
|
-
|
176
|
+
if (idOrUrl.match(/^wss?:/i)) {
|
177
|
+
return idOrUrl; // done!
|
192
178
|
}
|
193
179
|
// a target id is specified by the user
|
194
180
|
else {
|
195
|
-
devtools.List(options)
|
196
|
-
|
197
|
-
|
198
|
-
});
|
199
|
-
}).then(function (target) {
|
200
|
-
fetchFromObject(fulfill, reject, target);
|
201
|
-
}).catch(reject);
|
181
|
+
const targets = await devtools.List(options);
|
182
|
+
const object = targets.find((target) => target.id === idOrUrl);
|
183
|
+
return object.webSocketDebuggerUrl;
|
202
184
|
}
|
203
|
-
|
204
|
-
case 'object':
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
case 'function':
|
209
|
-
|
210
|
-
devtools.List(options)
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
return result;
|
216
|
-
}
|
217
|
-
}).then(function (target) {
|
218
|
-
fetchFromObject(fulfill, reject, target);
|
219
|
-
}).catch(reject);
|
220
|
-
break;
|
185
|
+
}
|
186
|
+
case 'object': {
|
187
|
+
const object = userTarget;
|
188
|
+
return object.webSocketDebuggerUrl;
|
189
|
+
}
|
190
|
+
case 'function': {
|
191
|
+
const func = userTarget;
|
192
|
+
const targets = await devtools.List(options);
|
193
|
+
const result = func(targets);
|
194
|
+
const object = typeof result === 'number' ? targets[result] : result;
|
195
|
+
return object.webSocketDebuggerUrl;
|
196
|
+
}
|
221
197
|
default:
|
222
|
-
|
198
|
+
throw new Error(`Invalid target argument "${this.target}"`);
|
223
199
|
}
|
224
|
-
}
|
225
|
-
}
|
200
|
+
}
|
226
201
|
|
227
|
-
//
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
try {
|
233
|
-
if (chrome.secure) {
|
234
|
-
url = url.replace(/^ws:/i, 'wss:');
|
235
|
-
}
|
236
|
-
chrome._ws = new WebSocket(url);
|
237
|
-
} catch (err) {
|
238
|
-
// handles bad URLs
|
239
|
-
reject(err);
|
240
|
-
return;
|
202
|
+
// fetch the protocol according to 'protocol' and 'local'
|
203
|
+
async _fetchProtocol(options) {
|
204
|
+
// if a protocol has been provided then use it
|
205
|
+
if (this.protocol) {
|
206
|
+
return this.protocol;
|
241
207
|
}
|
242
|
-
//
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
208
|
+
// otherwise user either the local or the remote version
|
209
|
+
else {
|
210
|
+
options.local = this.local;
|
211
|
+
return await devtools.Protocol(options);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
// establish the WebSocket connection and start processing user commands
|
216
|
+
_connectToWebSocket() {
|
217
|
+
return new Promise((fulfill, reject) => {
|
218
|
+
// create the WebSocket
|
219
|
+
try {
|
220
|
+
if (this.secure) {
|
221
|
+
this.webSocketUrl = this.webSocketUrl.replace(/^ws:/i, 'wss:');
|
222
|
+
}
|
223
|
+
this._ws = new WebSocket(this.webSocketUrl);
|
224
|
+
} catch (err) {
|
225
|
+
// handles bad URLs
|
226
|
+
reject(err);
|
227
|
+
return;
|
228
|
+
}
|
229
|
+
// set up event handlers
|
230
|
+
this._ws.on('open', () => {
|
231
|
+
fulfill();
|
232
|
+
});
|
233
|
+
this._ws.on('message', (data) => {
|
234
|
+
const message = JSON.parse(data);
|
235
|
+
this._handleMessage(message);
|
236
|
+
});
|
237
|
+
this._ws.on('close', (code) => {
|
238
|
+
this.emit('disconnect');
|
239
|
+
});
|
240
|
+
this._ws.on('error', (err) => {
|
241
|
+
reject(err);
|
242
|
+
});
|
255
243
|
});
|
256
|
-
}
|
257
|
-
}
|
244
|
+
}
|
258
245
|
|
259
|
-
// handle the messages read from the WebSocket
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
246
|
+
// handle the messages read from the WebSocket
|
247
|
+
_handleMessage(message) {
|
248
|
+
// command response
|
249
|
+
if (message.id) {
|
250
|
+
const callback = this._callbacks[message.id];
|
251
|
+
if (!callback) {
|
252
|
+
return;
|
253
|
+
}
|
254
|
+
// interpret the lack of both 'error' and 'result' as success
|
255
|
+
// (this may happen with node-inspector)
|
256
|
+
if (message.error) {
|
257
|
+
callback(true, message.error);
|
258
|
+
} else {
|
259
|
+
callback(false, message.result || {});
|
260
|
+
}
|
261
|
+
// unregister command response callback
|
262
|
+
delete this._callbacks[message.id];
|
263
|
+
// notify when there are no more pending commands
|
264
|
+
if (Object.keys(this._callbacks).length === 0) {
|
265
|
+
this.emit('ready');
|
266
|
+
}
|
274
267
|
}
|
275
|
-
//
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
268
|
+
// event
|
269
|
+
else if (message.method) {
|
270
|
+
const {method, params, sessionId} = message;
|
271
|
+
this.emit('event', message);
|
272
|
+
this.emit(method, params, sessionId);
|
273
|
+
this.emit(`${method}.${sessionId}`, params, sessionId);
|
280
274
|
}
|
281
275
|
}
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
276
|
+
|
277
|
+
// send a command to the remote endpoint and register a callback for the reply
|
278
|
+
_enqueueCommand(method, params, sessionId, callback) {
|
279
|
+
const id = this._nextCommandId++;
|
280
|
+
const message = {
|
281
|
+
id,
|
282
|
+
method,
|
283
|
+
sessionId,
|
284
|
+
params: params || {}
|
285
|
+
};
|
286
|
+
this._ws.send(JSON.stringify(message), (err) => {
|
287
|
+
if (err) {
|
288
|
+
// handle low-level WebSocket errors
|
289
|
+
if (typeof callback === 'function') {
|
290
|
+
callback(err);
|
291
|
+
}
|
292
|
+
} else {
|
293
|
+
this._callbacks[id] = callback;
|
294
|
+
}
|
295
|
+
});
|
286
296
|
}
|
287
297
|
}
|
288
298
|
|