IE11 support, markup fixes, caching fixes

This commit is contained in:
Mihail Slobodyanuk 2022-12-19 12:05:01 +02:00
parent 1e7d51bac6
commit 3999a62f54
8 changed files with 1278 additions and 25 deletions

View file

@ -98,6 +98,18 @@ else
PKGDISPLAYNAME="RiV-mesh Network" PKGDISPLAYNAME="RiV-mesh Network"
fi fi
cat > mesh-ui-ie.js << EOF
var ie = new ActiveXObject("InternetExplorer.Application");
ie.AddressBar = false;
ie.MenuBar = false;
ie.ToolBar = false;
ie.height = 960
ie.width = 706
ie.resizable = false
ie.Visible = true;
ie.Navigate("http://localhost:19019");
EOF
# Generate the wix.xml file # Generate the wix.xml file
cat > wix.xml << EOF cat > wix.xml << EOF
<?xml version="1.0" encoding="windows-1252"?> <?xml version="1.0" encoding="windows-1252"?>

View file

@ -0,0 +1,420 @@
"use strict";
var $ = function $(id) {
return document.getElementById(id);
};
var $$ = function $$(clazz) {
return document.getElementsByClassName(clazz);
};
function setPingValue(peer, value) {
var cellText;
var peerCell = $(peer);
if (!peerCell) return;
var peerTable = $("peer_list");
if (value === "-1") {
var peerAddress = $("label_" + peer);
peerAddress.style.color = "rgba(250,250,250,.5)";
} else {
cellText = document.createTextNode(value);
peerCell.appendChild(cellText);
var peerCellTime = $("time_" + peer);
var cellTextTime = document.createTextNode("ms");
peerCellTime.appendChild(cellTextTime);
}
peerCell.parentNode.classList.remove("is-hidden");
//sort table
moveRowToOrderPos(peerTable, 2, peerCell.parentNode);
}
function cmpTime(a, b) {
return a.textContent.trim() === "" ? 1 : a.textContent.trim() // using `.textContent.trim()` for test
.localeCompare(b.textContent.trim(), 'en', { numeric: true });
}
function moveRowToOrderPos(table, col, row) {
var tb = table.tBodies[0],
tr = tb.rows;
var i = 0;
for (; i < tr.length && cmpTime(row.cells[col], tr[i].cells[col]) >= 0; ++i) {}
if (i < tr.length && i != row.rowIndex) {
tb.deleteRow(row.rowIndex);
tb.insertBefore(row, tr[i]);
}
}
function openTab(element, tabName) {
// Declare all variables
var i, tabContent, tabLinks;
// Get all elements with class="content" and hide them
tabContent = $$("tab here");
for (i = 0; i < tabContent.length; i++) {
tabContent[i].className = "tab here is-hidden";
}
// Get all elements with class="tab" and remove the class "is-active"
tabLinks = $$("tab is-active");
for (i = 0; i < tabLinks.length; i++) {
tabLinks[i].className = "tab";
}
// Show the current tab, and add an "is-active" class to the button that opened the tab
$(tabName).className = "tab here";
element.parentElement.className = "tab is-active";
//refreshRecordsList();
}
function copy2clipboard(text) {
var textArea = document.createElement("textarea");
textArea.style.position = 'fixed';
textArea.style.top = 0;
textArea.style.left = 0;
// Ensure it has a small width and height. Setting to 1px / 1em
// doesn't work as this gives a negative w/h on some browsers.
textArea.style.width = '2em';
textArea.style.height = '2em';
// We don't need padding, reducing the size if it does flash render.
textArea.style.padding = 0;
// Clean up any borders.
textArea.style.border = 'none';
textArea.style.outline = 'none';
textArea.style.boxShadow = 'none';
// Avoid flash of the white box if rendered for any reason.
textArea.style.background = 'transparent';
textArea.value = text;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copying text command was ' + msg);
} catch (err) {
console.log('Oops, unable to copy');
}
document.body.removeChild(textArea);
showInfo('value copied successfully!');
}
function showInfo(text) {
var info = $("notification_info");
var message = $("info_text");
message.innerHTML = text;
info.className = "notification is-primary";
var button = $("info_close");
button.onclick = function () {
message.value = "";
info.className = "notification is-primary is-hidden";
};
setTimeout(button.onclick, 2000);
}
function showWindow(text) {
var info = $("notification_window");
var message = $("info_window");
message.innerHTML = text;
info.classList.remove("is-hidden");
var button_info_close = $("info_win_close");
button_info_close.onclick = function () {
message.value = "";
info.classList.add("is-hidden");
$("peer_list").remove();
};
var button_window_close = $("window_close");
button_window_close.onclick = function () {
message.value = "";
info.classList.add("is-hidden");
$("peer_list").remove();
};
var button_window_save = $("window_save");
button_window_save.onclick = function () {
message.value = "";
info.classList.add("is-hidden");
//todo save peers
var peers = document.querySelectorAll('*[id^="peer-"]');
var peer_list = [];
for (i = 0; i < peers.length; ++i) {
var p = peers[i];
if (p.checked) {
var peerURL = p.parentElement.parentElement.children[1].innerText;
peer_list.push(peerURL);
}
}
fetch('api/peers', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Riv-Save-Config': 'true'
},
body: JSON.stringify(peer_list)
}).catch(function (error) {
console.error('Error:', error);
});
$("peer_list").remove();
};
}
function add_table(peerList) {
var peers = [];
//const countries = Object.keys(peerList);
// get the reference for the body
var body = document.createElement("div");
// creates a <table> element and a <tbody> element
var tbl = document.createElement("table");
tbl.setAttribute('id', "peer_list");
//tbl.setAttribute('cellpadding', '10');
var tblBody = document.createElement("tbody");
// creating all cells
for (var c in peerList) {
var counter = 1;
for (var peer in peerList[c]) {
peers.push(peer);
// creates a table row
var row = document.createElement("tr");
row.className = "is-hidden";
var imgElement = document.createElement("td");
imgElement.className = "big-flag fi fi-" + ui.lookupCountryCodeByAddress(peer);
var peerAddress = document.createElement("td");
var cellText = document.createTextNode(peer);
peerAddress.appendChild(cellText);
peerAddress.setAttribute('id', "label_" + peer);
var peerPing = document.createElement("td");
peerPing.setAttribute('id', peer);
var peerPingTime = document.createElement("td");
peerPingTime.setAttribute('id', "time_" + peer);
var peerSelect = document.createElement("td");
var chk = document.createElement('input');
chk.setAttribute('type', 'checkbox');
chk.setAttribute('id', "peer-" + counter);
peerSelect.appendChild(chk);
row.appendChild(imgElement);
row.appendChild(peerAddress);
row.appendChild(peerPing);
row.appendChild(peerPingTime);
row.appendChild(peerSelect);
tblBody.appendChild(row);
}
}
// put the <tbody> in the <table>
tbl.appendChild(tblBody);
// appends <table> into <body>
body.appendChild(tbl);
// sets the border attribute of tbl to 2;
//tbl.setAttribute("border", "0");
showWindow(body.innerHTML);
return peers;
}
function togglePrivKeyVisibility() {
if (this.classList.contains("fa-eye")) {
this.classList.remove("fa-eye");
this.classList.add("fa-eye-slash");
$("priv_key_visible").innerHTML = $("priv_key").innerHTML;
} else {
this.classList.remove("fa-eye-slash");
this.classList.add("fa-eye");
$("priv_key_visible").innerHTML = "••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••";
}
}
function humanReadableSpeed(speed) {
var i = speed == 0 ? 0 : Math.floor(Math.log(speed) / Math.log(1024));
return (speed / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['Bps', 'kBps', 'MBps', 'GBps', 'TBps'][i];
}
var ui = ui || {
countries: []
};
ui.getAllPeers = function () {
if (!("_allPeersPromise" in ui)) {
ui._allPeersPromise = new Promise(function (resolve, reject) {
if ("_allPeers" in ui) resolve(ui._allPeers);else fetch('https://map.rivchain.org/rest/peers.json').then(function (response) {
return response.json();
}).then(function (data) {
var _loop = function _loop() {
var country = c.slice(0, -3);
var filtered = ui.countries.find(function (entry) {
return entry.name.toLowerCase() == country;
});
//let flagFile = filtered ? filtered["flag_4x3"] : "";
var flagCode = filtered ? filtered["code"] : "";
for (var peer in data[c]) {
data[c][peer].countryCode = flagCode;
}
};
// add country code to each peer
for (var c in data) {
_loop();
}
ui._allPeers = data;
resolve(ui._allPeers);
}).catch(reject);
}).finally(function () {
return delete ui._allPeersPromise;
});
}
return ui._allPeersPromise;
};
ui.showAllPeers = function () {
return ui.getAllPeers().then(function (peerList) {
var peers = add_table(peerList);
//start peers test
fetch('api/ping', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(peers)
}).catch(function (error) {
console.error('Error:', error);
});
}).catch(function (error) {
console.error(error);
});
};
ui.getConnectedPeers = function () {
return fetch('api/peers').then(function (response) {
return response.json();
});
};
var regexMulticast = /:\/\/\[fe80::/;
ui.updateConnectedPeersHandler = function (peers) {
$("peers").innerText = "";
var regexStrip = /%[^\]]*/gm;
var sorted = peers.map(function (peer) {
return { "url": peer["remote"], "isMulticast": peer["remote"].match(regexMulticast) };
}).sort(function (a, b) {
return a.isMulticast > b.isMulticast;
});
sorted.forEach(function (peer) {
var row = $("peers").appendChild(document.createElement('div'));
row.className = "overflow-ellipsis";
var flag = row.appendChild(document.createElement("span"));
if (peer.isMulticast) flag.className = "fa fa-thin fa-share-nodes peer-connected-fl";else flag.className = "fi fi-" + ui.lookupCountryCodeByAddress(peer.url) + " peer-connected-fl";
row.append(peer.url.replace(regexStrip, ""));
});
};
ui.updateStatus = function (peers) {
var status = "st-error";
if (peers) {
if (peers.length) {
var isNonMulticastExists = peers.filter(function (peer) {
return !peer["remote"].match(regexMulticast);
}).length;
status = isNonMulticastExists ? "st-multicast" : "st-connected";
} else {
status = "st-connecting";
}
}
Array.from($$("status")).forEach(function (node) {
return node.classList.add("is-hidden");
});
$(status).classList.remove("is-hidden");
};
ui.updateSpeed = function (peers) {
if (peers) {
var rsbytes = { "bytes_recvd": peers.reduce(function (acc, peer) {
return acc + peer.bytes_recvd;
}, 0),
"bytes_sent": peers.reduce(function (acc, peer) {
return acc + peer.bytes_sent;
}, 0),
"timestamp": Date.now() };
if ("_rsbytes" in ui) {
$("dn_speed").innerText = humanReadableSpeed((rsbytes.bytes_recvd - ui._rsbytes.bytes_recvd) * 1000 / (rsbytes.timestamp - ui._rsbytes.timestamp));
$("up_speed").innerText = humanReadableSpeed((rsbytes.bytes_sent - ui._rsbytes.bytes_sent) * 1000 / (rsbytes.timestamp - ui._rsbytes.timestamp));
}
ui._rsbytes = rsbytes;
} else {
delete ui._rsbytes;
$("dn_speed").innerText = "? Bs";
$("up_speed").innerText = "? Bs";
}
};
ui.updateConnectedPeers = function () {
return ui.getConnectedPeers().then(function (peers) {
ui.updateConnectedPeersHandler(peers);
ui.updateStatus(peers);
ui.updateSpeed(peers);
}).catch(function (error) {
$("peers").innerText = error.message;
ui.updateStatus();
ui.updateSpeed();
});
};
ui.lookupCountryCodeByAddress = function (address) {
for (var c in ui._allPeers) {
for (var peer in ui._allPeers[c]) {
if (peer == address) return ui._allPeers[c][peer].countryCode;
}
}
};
ui.getSelfInfo = function () {
return fetch('api/self').then(function (response) {
return response.json();
});
};
ui.updateSelfInfo = function () {
return ui.getSelfInfo().then(function (info) {
$("ipv6").innerText = info.address;
$("subnet").innerText = info.subnet;
$("pub_key").innerText = info.key;
$("priv_key").innerText = info.private_key;
$("ipv6").innerText = info.address;
$("version").innerText = info.build_version;
}).catch(function (error) {
$("ipv6").innerText = error.message;
});
};
ui.sse = new EventSource('/api/sse');
function main() {
window.addEventListener("load", function () {
$("showAllPeersBtn").addEventListener("click", ui.showAllPeers);
ui.getAllPeers().then(function () {
return ui.updateConnectedPeers();
});
setInterval(ui.updateConnectedPeers, 5000);
ui.updateSelfInfo();
//setInterval(ui.updateSelfInfo, 5000);
ui.sse.addEventListener("ping", function (e) {
var data = JSON.parse(e.data);
setPingValue(data.peer, data.value);
});
ui.sse.addEventListener("peers", function (e) {
ui.updateConnectedPeersHandler(JSON.parse(e.data));
});
});
}
main();

View file

@ -68,12 +68,9 @@ img {
display: block; display: block;
} }
html, body {
height: 100vh;
}
body { body {
max-width: 690px; max-width: 690px;
min-width: 690px;
margin: auto; margin: auto;
} }
@ -86,6 +83,13 @@ td.fi {
background-position: 0; background-position: 0;
} }
footer {
position:fixed;
bottom:0;
max-width: 690px;
margin-top: auto;
}
#footer-row td { #footer-row td {
padding: 10px; padding: 10px;
white-space: nowrap; white-space: nowrap;

View file

@ -229,7 +229,7 @@ function humanReadableSpeed(speed) {
return (speed / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['Bps', 'kBps', 'MBps', 'GBps', 'TBps'][i]; return (speed / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['Bps', 'kBps', 'MBps', 'GBps', 'TBps'][i];
} }
var ui = { var ui = ui || {
countries: [] countries: []
}; };
@ -372,10 +372,6 @@ ui.sse = new EventSource('/api/sse');
function main() { function main() {
fetch('country.json')
.then((response) => response.json())
.then((data) => { ui.countries = data });
window.addEventListener("load", () => { window.addEventListener("load", () => {
$("showAllPeersBtn").addEventListener("click", ui.showAllPeers); $("showAllPeersBtn").addEventListener("click", ui.showAllPeers);

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,6 @@
[ var ui = ui || {};
ui.countries = [
{ {
"capital": "Georgetown", "capital": "Georgetown",
"code": "ac", "code": "ac",

View file

@ -11,11 +11,27 @@
<link rel="stylesheet" href="assets/bulmaswatch.min.css" type="text/css"> <link rel="stylesheet" href="assets/bulmaswatch.min.css" type="text/css">
<link rel="stylesheet" href="assets/flag-icons.css" type="text/css"> <link rel="stylesheet" href="assets/flag-icons.css" type="text/css">
<link rel="stylesheet" href="assets/mesh-ui.css" type="text/css"> <link rel="stylesheet" href="assets/mesh-ui.css" type="text/css">
<script type="application/javascript" src="assets/mesh-ui.js"></script> <script type="application/javascript" src="country.json"></script>
<!--script type="application/javascript" src="assets/mesh-ui.js"></script-->
<script>
var script = document.createElement('script');
//load polyfills + EC5 for IE or usual for rest
if (window.document.documentMode) {
script.src = "assets/polyfills.js";
script.onload = function () {
var ec5 = document.createElement('script');
ec5.src = "assets/mesh-ui-es5.js";
document.head.appendChild(ec5);
};
} else {
script.src = "assets/mesh-ui.js";
}
document.head.appendChild(script);
</script>
</head> </head>
<body> <body class="hero is-fullheight">
<div class="container hero is-fullheight"> <div>
<div class="box is-hidden" id="notification_window"> <div class="box is-hidden" id="notification_window">
<div style="z-index: 9;" class="notification is-primary"> <div style="z-index: 9;" class="notification is-primary">
<button class="delete" id="info_win_close"></button> <button class="delete" id="info_win_close"></button>
@ -53,7 +69,7 @@
preserveAspectRatio="xMidYMid meet" viewBox="0 0 42 42"> preserveAspectRatio="xMidYMid meet" viewBox="0 0 42 42">
<path <path
d="M18.5 35.5l-8 2c-.48.04-1 .52-1 1v1c0 .5.47 1 1 1h20c.43 0 1-.41 1-1v-1c-.02-.52-.55-.98-1-1l-8-2h-4zm19-1c2.59 0 3-.529 3-3v-26c0-2.391-.55-3-3-3h-34c-2.43 0-3 .54-3 3v26c0 2.51.529 3 3 3h34zm-2-27v22h-30v-22h30z" d="M18.5 35.5l-8 2c-.48.04-1 .52-1 1v1c0 .5.47 1 1 1h20c.43 0 1-.41 1-1v-1c-.02-.52-.55-.98-1-1l-8-2h-4zm19-1c2.59 0 3-.529 3-3v-26c0-2.391-.55-3-3-3h-34c-2.43 0-3 .54-3 3v26c0 2.51.529 3 3 3h34zm-2-27v22h-30v-22h30z"
fill="white" /> fill="white" ></path>
</svg> </svg>
</span> </span>
<span>My Node</span> <span>My Node</span>
@ -67,8 +83,8 @@
style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);"
preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"> preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32">
<g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"> <g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
<path d="M5 15v15h22V15zm4 0C9 9 9 5 16 5s7 4 7 10m-7 5v3" /> <path d="M5 15v15h22V15zm4 0C9 9 9 5 16 5s7 4 7 10m-7 5v3" ></path>
<circle cx="16" cy="24" r="1" /> <circle cx="16" cy="24" r="1" ></circle>
</g> </g>
</svg> </svg>
</span> </span>
@ -82,10 +98,10 @@
focusable="false" width="1em" height="1em" focusable="false" width="1em" height="1em"
style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);"
preserveAspectRatio="xMidYMid meet" viewBox="0 0 48 48"> preserveAspectRatio="xMidYMid meet" viewBox="0 0 48 48">
<path fill="#2196F3" d="M37 40H11l-6 6V12c0-3.3 2.7-6 6-6h26c3.3 0 6 2.7 6 6v22c0 3.3-2.7 6-6 6z" /> <path fill="#2196F3" d="M37 40H11l-6 6V12c0-3.3 2.7-6 6-6h26c3.3 0 6 2.7 6 6v22c0 3.3-2.7 6-6 6z" ></path>
<g fill="#fff"> <g fill="#fff">
<path d="M22 20h4v11h-4z" /> <path d="M22 20h4v11h-4z" ></path>
<circle cx="24" cy="15" r="2" /> <circle cx="24" cy="15" r="2" ></circle>
</g> </g>
</svg> </svg>
</span> </span>
@ -165,7 +181,8 @@
</div> </div>
</div> </div>
<footer class="is-flex-align-items-flex-end" style="margin-top: auto"> </div>
<footer>
<hr style="margin: 0px;background-color: #5d656d;"> <hr style="margin: 0px;background-color: #5d656d;">
<table class="content"><tr id="footer-row"> <table class="content"><tr id="footer-row">
<td id="version" style="padding-left: 50px;">v123456</td> <td id="version" style="padding-left: 50px;">v123456</td>
@ -181,6 +198,4 @@
</tr></table> </tr></table>
</footer> </footer>
</div>
</html> </html>

View file

@ -254,10 +254,16 @@ func (a *AdminSocket) StartHttpServer(configFn string, nc *config.NodeConfig) {
a.log.Errorln("An error occurred parsing http address:", err) a.log.Errorln("An error occurred parsing http address:", err)
return return
} }
addNoCacheHeaders := func(w http.ResponseWriter) {
w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Add("Pragma", "no-cache")
w.Header().Add("Expires", "0")
}
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Following methods are allowed: getself, getpeers. litening"+u.Host) fmt.Fprintf(w, "Following methods are allowed: getself, getpeers. litening"+u.Host)
}) })
http.HandleFunc("/api/self", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/api/self", func(w http.ResponseWriter, r *http.Request) {
addNoCacheHeaders(w)
switch r.Method { switch r.Method {
case "GET": case "GET":
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
@ -316,6 +322,7 @@ func (a *AdminSocket) StartHttpServer(configFn string, nc *config.NodeConfig) {
return nil return nil
} }
addNoCacheHeaders(w)
switch r.Method { switch r.Method {
case "GET": case "GET":
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
@ -365,6 +372,7 @@ func (a *AdminSocket) StartHttpServer(configFn string, nc *config.NodeConfig) {
}) })
http.HandleFunc("/api/sse", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/api/sse", func(w http.ResponseWriter, r *http.Request) {
addNoCacheHeaders(w)
switch r.Method { switch r.Method {
case "GET": case "GET":
w.Header().Add("Content-Type", "text/event-stream") w.Header().Add("Content-Type", "text/event-stream")
@ -399,9 +407,7 @@ func (a *AdminSocket) StartHttpServer(configFn string, nc *config.NodeConfig) {
if docFs == "" { if docFs == "" {
var nocache = func(fs http.Handler) http.HandlerFunc { var nocache = func(fs http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate") addNoCacheHeaders(w)
w.Header().Add("Pragma", "no-cache")
w.Header().Add("Expires", "0")
fs.ServeHTTP(w, r) fs.ServeHTTP(w, r)
} }
} }