Rss-Bridge/static/connectivity.js

256 lines
5.9 KiB
JavaScript
Raw Normal View History

action: Add action to check bridge connectivity (#1147) * action: Add action to check bridge connectivity It is currently not simply possible to check if the remote server for a bridge is reachable or not, which means some of the bridges might no longer work because the server is no longer on the internet. In order to find those bridges we can either check each bridge individually (which takes a lot of effort), or use an automated script to do this for us. If a server is no longer reachable it could mean that it is temporarily unavailable, or shutdown permanently. The results of this script will at least help identifying such servers. * [Connectivity] Use Bootstrap container to properly display contents * [Connectivity] Limit connectivity checks to debug mode Connectivity checks take a long time to execute and can require a lot of bandwidth. Therefore, administrators should be able to determine when and who is able to utilize this action. The best way to prevent regular users from accessing this action is by making it available in debug mode only (public servers should never run in debug mode anyway). * [Connectivity] Split implemenation into multiple files * [Connectivity] Make web page responsive to user input * [Connectivity] Make status message sticky * [Connectivity] Add icon to the status message * [contents] Add the ability for getContents to return header information * [Connectivity] Add header information to the reply Json data * [Connectivity] Add new status (blue) for redirected sites Also adds titles to status icons (Successful, Redirected, Inactive, Failed) * [Connectivity] Fix show doesn't work for inactive bridges * [Connectivity] Fix typo * [Connectivity] Catch errors in promise chains * [Connectivity] Allow search by status and update dynamically * [Connectivity] Add a progress bar * [Connectivity] Use bridge factory * [Connectivity] Import Bootstrap v4.3.1 CSS
2019-10-31 22:02:38 +01:00
var remote = location.href.substring(0, location.href.lastIndexOf("/"));
var bridges = [];
var abort = false;
window.onload = function() {
fetch(remote + '/index.php?action=list').then(function(response) {
return response.text()
}).then(function(data){
processBridgeList(data);
}).catch(console.log.bind(console)
);
}
function processBridgeList(data) {
var list = JSON.parse(data);
buildTable(list);
buildBridgeQueue(list);
checkNextBridgeAsync();
}
function buildTable(bridgeList) {
var table = document.createElement('table');
table.classList.add('table');
var thead = document.createElement('thead');
thead.innerHTML = `
<tr>
<th scope="col">Bridge</th>
<th scope="col">Result</th>
</tr>`;
var tbody = document.createElement('tbody');
for (var bridge in bridgeList.bridges) {
var tr = document.createElement('tr');
tr.classList.add('bg-secondary');
tr.id = bridge;
var td_bridge = document.createElement('td');
td_bridge.innerText = bridgeList.bridges[bridge].name;
// Link to the actual bridge on index.php
var a = document.createElement('a');
a.href = remote + "/index.php?show_inactive=1#bridge-" + bridge;
a.target = '_blank';
a.innerText = '[Show]';
a.style.marginLeft = '5px';
a.style.color = 'black';
td_bridge.appendChild(a);
tr.appendChild(td_bridge);
var td_result = document.createElement('td');
if (bridgeList.bridges[bridge].status === 'active') {
td_result.innerHTML = '<i title="Scheduled" class="fas fa-hourglass-start"></i>';
} else {
td_result.innerHTML = '<i title="Inactive" class="fas fa-times-circle"></i>';
}
tr.appendChild(td_result);
tbody.appendChild(tr);
}
table.appendChild(thead);
table.appendChild(tbody);
var content = document.getElementById('main-content');
content.appendChild(table);
}
function buildBridgeQueue(bridgeList) {
for (var bridge in bridgeList.bridges) {
if (bridgeList.bridges[bridge].status !== 'active')
continue;
bridges.push(bridge);
}
}
function checkNextBridgeAsync() {
return new Promise((resolve) => {
var msg = document.getElementById('status-message');
var icon = document.getElementById('status-icon');
if (bridges.length === 0) {
msg.classList.remove('alert-primary');
msg.classList.add('alert-success');
msg.getElementsByTagName('span')[0].textContent = 'Done';
icon.classList.remove('fa-sync');
icon.classList.add('fa-check');
} else {
var bridge = bridges.shift();
msg.getElementsByTagName('span')[0].textContent = 'Processing ' + bridge + '...';
fetch(remote + '/index.php?action=Connectivity&bridge=' + bridge)
.then(function(response) { return response.text() })
.then(JSON.parse)
.then(processBridgeResultAsync)
.then(markBridgeSuccessful, markBridgeFailed)
.then(checkAbortAsync)
.then(checkNextBridgeAsync, abortChecks)
.catch(console.log.bind(console));
search(); // Dynamically update search results
updateProgressBar();
}
resolve();
});
}
function abortChecks() {
return new Promise((resolve) => {
var msg = document.getElementById('status-message');
msg.classList.remove('alert-primary');
msg.classList.add('alert-warning');
msg.getElementsByTagName('span')[0].textContent = 'Aborted';
var icon = document.getElementById('status-icon');
icon.classList.remove('fa-sync');
icon.classList.add('fa-ban');
bridges.forEach((bridge) => {
markBridgeAborted(bridge);
})
resolve();
});
}
function processBridgeResultAsync(result) {
return new Promise((resolve, reject) => {
if (result.successful) {
resolve(result);
} else {
reject(result);
}
});
}
function markBridgeSuccessful(result) {
return new Promise((resolve) => {
var tr = document.getElementById(result.bridge);
tr.classList.remove('bg-secondary');
if (result.http_code == 200) {
tr.classList.add('bg-success');
tr.children[1].innerHTML = '<i title="Successful" class="fas fa-check"></i>';
} else {
tr.classList.add('bg-primary');
tr.children[1].innerHTML = '<i title="Redirected" class="fas fa-directions"></i>';
}
resolve();
});
}
function markBridgeFailed(result) {
return new Promise((resolve) => {
var tr = document.getElementById(result.bridge);
tr.classList.remove('bg-secondary');
tr.classList.add('bg-danger');
tr.children[1].innerHTML = '<i title="Failed" class="fas fa-exclamation-triangle"></i>';
resolve();
});
}
function markBridgeAborted(bridge) {
return new Promise((resolve) => {
var tr = document.getElementById(bridge);
tr.classList.remove('bg-secondary');
tr.classList.add('bg-warning');
tr.children[1].innerHTML = '<i title="Aborted" class="fas fa-ban"></i>';
resolve();
});
}
function checkAbortAsync() {
return new Promise((resolve, reject) => {
if (abort) {
reject();
return;
}
resolve();
});
}
function updateProgressBar() {
// This will break if the table changes
var total = document.getElementsByTagName('tr').length - 1;
var current = bridges.length;
var progress = (total - current) * 100 / total;
var progressBar = document.getElementsByClassName('progress-bar')[0];
if(progressBar){
progressBar.setAttribute('aria-valuenow', progress.toFixed(0));
progressBar.style.width = progress.toFixed(0) + '%';
}
}
function stopConnectivityChecks() {
abort = true;
}
function search() {
var input = document.getElementById('search');
var filter = input.value.toUpperCase();
var table = document.getElementsByTagName('table')[0];
var tr = table.getElementsByTagName('tr');
for (var i = 0; i < tr.length; i++) {
var td1 = tr[i].getElementsByTagName('td')[0];
var td2 = tr[i].getElementsByTagName('td')[1];
if (td1) {
var txtValue = td1.textContent || td1.innerText;
var title = '';
if(td2.getElementsByTagName('i')[0]) {
title = td2.getElementsByTagName('i')[0].title;
}
if (txtValue.toUpperCase().indexOf(filter) > -1
|| title.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = '';
} else {
tr[i].style.display = 'none';
}
}
}
}