Commit 8ec9dd1d authored by lukas.niegsch's avatar lukas.niegsch

wip: implementing dynamic devtools API

parent 81932ac6
<!DOCTYPE html>
<html>
<!--
This will be removed later. Implementing each function inside CDP
manually takes is too much work. So gadget_devtools.html will provide
a dynamic solution.
--->
<head>
<title>Browser Gadget</title>
<script src="include/nexedi/rsvp.js"></script>
......@@ -7,4 +12,9 @@
<script src="include/nexedi/renderjs.js"></script>
<script src="gadget_browser.js"></script>
</head>
<div
data-gadget-url="gadget_devtools.html"
data-gadget-scope="devtools"
data-gadget-sandbox="public">
</div>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<!--
This gadget controls an remote browser via the chrome devtools protocol.
The remote browser must support the protocol, run in headless mode, and
must be available with the following parameters:
BROWSER_URL
BROWSER_USERNAME
BROWSER_PASSWORD
This gadget also requires that Cross-Origin Resource Sharing with the
BROWSER_URL is enabled.
Example (chromium running on localhost):
google-chrome-stable --headless --remote-debugging-port=9222
-> BROWSER_URL="http://localhost:9222"
-> BROWSER_USERNAME="ignored"
-> BROWSER_PASSWORD="ignored"
Example (chromium running on slapos):
slapos request ${SOFTWARE_NAME} ${SOFTWARE_RELEASE_URI}
-> BROWSER_URL="https://softinstXXXXX.host.vifib.net"
-> BROWSER_USERNAME="admin"
-> BROWSER_PASSWORD="password"
Usage:
var devtools;
this.getDeclaredGadget("devtools")
.push(function (subgadget) {
devtools = subgadget;
return devtools.Page.enable();
})
.push(function () {
return devtools.Page.navigate({url: "https://www.example.com"});
})
.push(function () {
return devtools.Page.loadEventFired();
})
The variable devtools contains this gadget. This gadget has several
subobjects according to the protocol, e.g. Page. Each subobjects has
methods and events. Both of them can be used like regular functions.
Calling a method will trigger it, and calling an event will wait
until the browser triggers it. Some methods will return some types,
which we encode as objects. See the references on how to use the
different methods, events, and types.
References:
https://chromedevtools.github.io/devtools-protocol
--->
<head>
<title>Devtools Gadget</title>
<script src="include/nexedi/rsvp.js"></script>
<script src="include/nexedi/renderjs.js"></script>
<script src="gadget_devtools.js"></script>
</head>
</html>
\ No newline at end of file
// todo: move outside of this gadget
var BROWSER_URL = "http://localhost:9222";
var BROWSER_USERNAME = "ignored";
var BROWSER_PASSWORD = "ignored";
(function(window, rJS, RSVP) {
"use strict";
/**
* Makes an HTTP get request to the browser to retrieve some JSON data.
*
* @param {String} path The path of the json file.
* @returns The promise for the the JSON data as object.
*/
function getBrowserJSON (path) {
var callback = (resolve, reject) => {
var request = new XMLHttpRequest();
var url = (new URL(path, BROWSER_URL)).href;
request.open("GET", url, true, BROWSER_USERNAME, BROWSER_PASSWORD);
request.withCredentials = true;
request.onload = () => {
resolve(JSON.parse(request.responseText));
}
request.onerror = (error) => {
reject("Could not connect to browser!");
}
request.send();
}
return RSVP.Queue().push(function () {
return new RSVP.Promise(callback);
});
}
/**
* Returns the devtools API for the given domain. Domains are defined
* by the devtools protocol, e.g. Page. Each domain defines multiple
* methods, events, and types.
*
* @param {object} domain The domain data from the devtools API.
* @returns The promise for the devtools API object and its name.
*/
function getDevtoolsAPI(domain) {
var callback = (resolve) => {
console.log(domain.domain);
resolve({name: domain.domain, object: null});
}
return RSVP.Queue().push(function () {
return new RSVP.Promise(callback);
});
}
var gadget = rJS(window);
gadget.declareService(function () {
return getBrowserJSON("json/protocol")
.push(function (result) {
var promises = [];
for (let i = 0; i < result.domains.length; i++) {
promises.push(getDevtoolsAPI(result.domains[i]));
}
return RSVP.all(promises);
})
.push(function (result) {
for (let i = 0; i < result.length; i++) {
gadget[result[i].name] = result[i].object;
}
})
})
}(window, rJS, RSVP));
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment