/**
* @module graphRefresh
* @file graphRefresh.js - Dynamically refreshes the I2PSnark download speed graph.
* @description Fetches a bandwidth graph image from the I2P stats servlet at a configurable
* interval, converts it to a blob URL, and applies it as a CSS custom property so the UI
* can display a live download graph. Also applies the graph as a background in the message
* log when available. Auto-disables on HTTP 400 errors.
* @author dr|3d
* @license AGPL3 or later
*/
/**
* @type {number}
* @description Timestamp of the last graph refresh in milliseconds.
*/
let lastSnarkGraphRefresh = 0;
/**
* @type {boolean}
* @description Whether graph fetching is enabled; set to false on HTTP 400 errors.
*/
let graphEnabled = true;
/**
* @type {?string}
* @description The blob URL of the last applied graph image, revoked when replaced.
*/
let currentGraphUrl = null;
/**
* @type {number}
* @description Counter tracking how many times the graph has been refreshed.
*/
let refreshCount = 0;
/**
* @type {?HTMLElement}
* @description The #noload element, used to determine refresh interval timing.
*/
const noload = document.getElementById("noload");
/**
* @function refreshGraph
* @description Fetches the I2PSnark bandwidth graph image if the refresh interval has elapsed
* and graph fetching is enabled. Applies the result as a blob URL to the CSS custom property
* --snarkGraph, revoking the previous blob. Disables graph fetching on HTTP 400 errors.
* @returns {void}
* @example
* // Manually trigger a graph refresh
* refreshGraph();
*/
function refreshGraph() {
const now = Date.now();
const graphcss = document.getElementById("graphcss");
const graphUrlBase = "/viewstat.jsp?stat=[I2PSnark] InBps&showEvents=false&" +
"period=60000&periodCount=1440&end=0&width=2000&height=160&hideLegend=true&" +
"hideTitle=true&hideGrid=true&";
if ((now - lastSnarkGraphRefresh < 5 * 60 * 1000 && refreshCount !== 0) || !graphEnabled) {return;}
lastSnarkGraphRefresh = now;
const graphUrl = graphUrlBase + "t=" + now;
const applyGraph = (cssValue) => {
if (graphcss) {graphcss.innerText = ":root{--snarkGraph:" + cssValue + "}";}
};
fetch(graphUrl).then(response => {
if (response.ok) {return response.blob();}
if (response.status === 400) {
graphEnabled = false;
throw new Error("400 Bad Request");
}
throw new Error("Network response was not ok");
}).then(blob => {
const graphDataUrl = URL.createObjectURL(blob);
if (currentGraphUrl) {URL.revokeObjectURL(currentGraphUrl);}
currentGraphUrl = graphDataUrl;
applyGraph("url('" + graphDataUrl + "')");
refreshCount++;
}).catch(error => {
if (error.message === "400 Bad Request" || !graphEnabled) {
if (graphcss) {graphcss.textContent = "";}
return;
}
});
}
/**
* @type {?number}
* @description The interval ID for the periodic graph refresh timer.
*/
let snarkGraphIntervalId;
if (!snarkGraphIntervalId) {
const intervalTime = noload ? 5 * 60 * 1000 : 15 * 60 * 1000;
snarkGraphIntervalId = setInterval(refreshGraph, intervalTime);
}
/**
* @function clearIntervalAndAbort
* @description Clears the graph refresh interval timer. Called on page unload to prevent
* memory leaks and unnecessary network requests.
* @returns {void}
*/
function clearIntervalAndAbort() {clearInterval(snarkGraphIntervalId);}
window.addEventListener("beforeunload", clearIntervalAndAbort);
document.addEventListener("DOMContentLoaded", refreshGraph);