Skip to content

Commit

Permalink
Chrome CLI Runner to facilitate an async exit.
Browse files Browse the repository at this point in the history
* We now load a headless chrome platform ONLY if Chrome CLIRunner is being used
* We inhibit a default exit from CDP interface if Kernel#exit hasn't been called
  (and opal-platform has been loaded)
* We modify Kernel#exit to run a special alert message to communicate with
  Chrome CDP interface (we would have sent an exception, but it doesn't
  bubble in the async mess - perhaps it will once we migrate to PromiseV2)

Thanks to Brandon Gastelo for spotting this bug.

Ref: opal-rspec#89
  • Loading branch information
hmdne authored and elia committed Oct 5, 2022
1 parent e6a69ca commit a9f3f4a
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 5 deletions.
1 change: 1 addition & 0 deletions lib/opal/cli_runners/chrome.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def prepare_files_in(dir)
<meta charset='utf-8'>
<script src='./source-map-support.js'></script>
<script>
window.opalheadlesschrome = true;
sourceMapSupport.install({
retrieveSourceMap: function(path) {
return path.endsWith('/index.#{ext}') ? {
Expand Down
21 changes: 19 additions & 2 deletions lib/opal/cli_runners/chrome_cdp_interface.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,34 @@
else
`Page.handleJavaScriptDialog({accept: false})`
end
elsif `dialog.type` == 'alert' && `dialog.message` == 'opalheadlesschromeexit'
# A special case of an alert with a magic string "opalheadlesschromeexit".
# This denotes that `Kernel#exit` has been called. We would have rather used
# an exception here, but they don't bubble sometimes.
%x{
Page.handleJavaScriptDialog({accept: true});
Runtime.evaluate({ expression: "window.OPAL_EXIT_CODE" }).then(function(output) {
client.close();
if (typeof(output.result) !== "undefined" && output.result.type === "number") {
process.exit(output.result.value);
} else {
process.exit(0);
}
});
}
end
}
});
Page.loadEventFired(() => {
Runtime.evaluate({ expression: "window.OPAL_EXIT_CODE" }).then(function(output) {
client.close();
if (typeof(output.result) !== "undefined" && output.result.type === "number") {
client.close();
process.exit(output.result.value);
} else if (typeof(output.result) !== "undefined" && output.result.type === "string" && output.result.value === "noexit") {
// do nothing, we have headless chrome support enabled and there are most probably async events awaiting
} else {
client.close();
process.exit(0);
}
})
Expand Down
8 changes: 6 additions & 2 deletions stdlib/headless_chrome.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
%x{
// Inhibit the default exit behavior
window.OPAL_EXIT_CODE = "noexit";
Opal.exit = function(code) {
// You can't exit from the browser.
// The first call to Opal.exit should save an exit code.
// All next invocations must be ignored.
// Then we send an event to Chrome CDP Interface that we are finished
if (typeof(window.OPAL_EXIT_CODE) === "undefined") {
if (window.OPAL_EXIT_CODE === "noexit") {
window.OPAL_EXIT_CODE = code;
window.alert("opalheadlesschromeexit");
}
}
}
2 changes: 1 addition & 1 deletion stdlib/opal-platform.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
browser = `typeof(document) !== "undefined"`
node = `typeof(process) !== "undefined" && process.versions && process.versions.node`
nashorn = `typeof(Java) !== "undefined" && Java.type`
headless_chrome = `typeof(navigator) !== "undefined" && /\bHeadlessChrome\//.test(navigator.userAgent)`
headless_chrome = `typeof(opalheadlesschrome) !== 'undefined'`
gjs = `typeof(window) !== "undefined" && typeof(GjsFileImporter) !== 'undefined'`
quickjs = `typeof(window) === "undefined" && typeof(__loadScript) !== 'undefined'`
opal_miniracer = `typeof(opalminiracer) !== 'undefined'`
Expand Down

0 comments on commit a9f3f4a

Please sign in to comment.