Add files for rudimentary Electron GUI

This commit is contained in:
David Anderson 2019-06-21 16:22:55 -07:00
parent fdc6ed50a3
commit 63860bd95f
3 changed files with 186 additions and 0 deletions

View File

@ -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>

View File

@ -0,0 +1,12 @@
html, body, .container-fluid {
height: 100%;
#background-color: #111;
}
html {
-webkit-app-region: drag;
}
.container-fluid {
padding: 25px;
}

View File

@ -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();
});
});
})