mirror of https://github.com/BOINC/boinc.git
Add files for rudimentary Electron GUI
This commit is contained in:
parent
fdc6ed50a3
commit
63860bd95f
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>BOINC</title>
|
||||
|
||||
<!-- Stylesheets -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
delete module.exports
|
||||
</script>
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.bundle.min.js"></script>
|
||||
<script src="./window.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container-fluid">
|
||||
<!-- <canvas class="chart"></canvas> -->
|
||||
<p>
|
||||
<input type="button" value = "Suspend" onclick="suspend()">
|
||||
<p>
|
||||
|
||||
Host: <span id="domain_name"></span>
|
||||
<p>
|
||||
<h3>Projects:</h3>
|
||||
<span id="projects"></span>
|
||||
<p>
|
||||
<h3>Tasks:</h3>
|
||||
<span id="tasks"></span>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
html, body, .container-fluid {
|
||||
height: 100%;
|
||||
#background-color: #111;
|
||||
}
|
||||
|
||||
html {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
padding: 25px;
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
// This is a proof of concept for an electron-based BOINC GUI,
|
||||
// showing how to do GUI RPCs to the client.
|
||||
//
|
||||
// I developed this by starting with one of electron's "simple samples" (activity-monitor)
|
||||
// and replacing the files index.html, styles.css, and window.js
|
||||
//
|
||||
// Run this on a host with a running BOINC client,
|
||||
// in a directory with the GUI password file (gui_rpc_auth.cfg).
|
||||
//
|
||||
// Some next steps:
|
||||
// - do periodic RPCs to update state information
|
||||
// - add menus and dialogs
|
||||
// - Turn the Suspend button into a never/prefs/always control
|
||||
|
||||
const os = require('os')
|
||||
const fs = require('fs')
|
||||
const crypto = require('crypto')
|
||||
|
||||
var auth_id = 0;
|
||||
var auth_seqno = 1;
|
||||
var passwd;
|
||||
var http = new XMLHttpRequest();
|
||||
|
||||
var state; // result of get_state()
|
||||
|
||||
// read RPC password from file
|
||||
//
|
||||
function read_password() {
|
||||
let x = String(fs.readFileSync("gui_rpc_auth.cfg"));
|
||||
passwd = x.trim();
|
||||
}
|
||||
|
||||
// initiate a GUI RPC, passing authentication info if needed
|
||||
// returns a Promise; passes reply XML to the resolve function
|
||||
//
|
||||
function gui_rpc(request) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
http.onreadystatechange = function() {
|
||||
if (http.readyState != 4) return;
|
||||
if (http.status == 200) {
|
||||
//console.log('got response: ' + http.responseText);
|
||||
resolve(http.responseText);
|
||||
} else {
|
||||
reject(http);
|
||||
}
|
||||
};
|
||||
http.open("POST", "http://localhost:31416", true);
|
||||
if (auth_id) {
|
||||
http.setRequestHeader("Auth-ID", auth_id);
|
||||
console.log("request "+request+ " auth ID " + auth_id + " seqno " + auth_seqno);
|
||||
http.setRequestHeader("Auth-Seqno", auth_seqno);
|
||||
var s = String(auth_seqno);
|
||||
var x = crypto.createHash('md5').update(s+passwd).digest("hex");
|
||||
http.setRequestHeader("Auth-Hash", x);
|
||||
auth_seqno++;
|
||||
}
|
||||
http.send(request);
|
||||
});
|
||||
}
|
||||
|
||||
// Do a set_run_mode() RPC
|
||||
//
|
||||
function set_run_mode(mode) {
|
||||
return gui_rpc("<set_run_mode><"+mode+"/></set_run_mode>").then(function(reply) {
|
||||
console.log("set run mode");
|
||||
});
|
||||
}
|
||||
|
||||
// get authentication ID
|
||||
//
|
||||
function authorize() {
|
||||
read_password();
|
||||
return gui_rpc("<get_auth_id/>").then(function(reply) {
|
||||
x = new DOMParser().parseFromString(reply, "text/xml");
|
||||
auth_id = x.getElementsByTagName("auth_id")[0].childNodes[0].nodeValue;
|
||||
console.log("auth_id: "+auth_id);
|
||||
});
|
||||
}
|
||||
|
||||
// do a get_state() RPC
|
||||
//
|
||||
function get_state() {
|
||||
return gui_rpc("<get_state/>").then(function(reply) {
|
||||
//console.log("reply:" + reply);
|
||||
parser = new DOMParser();
|
||||
state = parser.parseFromString(reply, "text/xml");
|
||||
});
|
||||
}
|
||||
|
||||
function suspend() {
|
||||
set_run_mode("never").then(function() {
|
||||
});
|
||||
}
|
||||
|
||||
// display the result of get_state()
|
||||
//
|
||||
function show_state() {
|
||||
// show host name
|
||||
//
|
||||
d = state.querySelector("domain_name").textContent;
|
||||
console.log('domain name', d);
|
||||
document.querySelector('#domain_name').innerHTML = d;
|
||||
|
||||
// show projects
|
||||
//
|
||||
x = '';
|
||||
state.querySelectorAll("project").forEach((p)=>{
|
||||
x += '<br>'+ p.querySelector('project_name').textContent;
|
||||
});
|
||||
document.querySelector('#projects').innerHTML = x;
|
||||
|
||||
// show tasks
|
||||
x = '';
|
||||
state.querySelectorAll("result").forEach((r)=>{
|
||||
x += '<br>'+ r.querySelector('name').textContent;
|
||||
});
|
||||
document.querySelector('#tasks').innerHTML = x;
|
||||
}
|
||||
|
||||
|
||||
$(() => { // shorthand for document ready
|
||||
// get authorization ID
|
||||
//
|
||||
authorize().then(function() {
|
||||
// then get state and show it
|
||||
//
|
||||
get_state().then(function() {
|
||||
show_state();
|
||||
});
|
||||
});
|
||||
})
|
Loading…
Reference in New Issue