all-in-one/php/public/container_events_log_client.js

123 lines
4.4 KiB
JavaScript
Raw Normal View History

class ContainerEventsLogClient {
overlayElem;
overlayLogElem;
pollingFrequencySec = 5;
pollingIntervalId = null;
etag = '';
debugLogging = false;
constructor() {
this.overlayElem = document.getElementById('overlay');
this.fetchAndShow();
this.pollingIntervalId = setInterval(() => this.fetchAndShow(), this.pollingFrequencySec * 1000);
}
#debug(message) {
if (this.debugLogging) {
console.debug(message);
}
}
stopPolling() {
if (this.pollingIntervalId) {
clearInterval(this.pollingIntervalId);
}
}
async storeEtag(response) {
const newEtag = response.headers.get('etag');
if (newEtag) {
this.etag = newEtag;
}
return response;
}
async getTextFromResponse(response) {
if (response.status >= 200 && response.status < 300) {
return response.text();
} else if (response.status === 304) {
this.#debug('Cache hit, nothing to do');
return Promise.reject();
// Cache hit, nothing to do.
} else {
console.error(`Got response status ${response.status}, cannot continue`);
return Promise.reject();
}
}
showLoggedEventsInOverlay(loggedEvents) {
this.overlayLogElem ||= document.getElementById('overlay-log');
this.overlayLogElem.classList.add('visible');
loggedEvents.forEach((loggedEvent) => {
const elem = this.overlayLogElem.querySelector(`.${loggedEvent.id}`);
if (elem) {
elem.lastElementChild.textContent = loggedEvent.message;
} else {
const capitalizedContainerName = loggedEvent.id.replace('nextcloud-aio-', '').replace('-', ' ').replace(/(^|\s)[a-z]/gi, (letter) => letter.toUpperCase());
const newElem = document.createElement('div');
newElem.className = loggedEvent.id;
const nameElem = document.createElement('span');
nameElem.textContent = `${capitalizedContainerName}:`;
const messageElem = document.createElement('span');
messageElem.textContent = loggedEvent.message;
newElem.append(nameElem, messageElem);
this.overlayLogElem.append(newElem);
}
});
}
showLoggedEventsInContainerList(loggedEvents) {
this.containerElems ||= new Map(Array.from(document.getElementsByClassName('container-elem')).map((elem) => [elem.dataset.containerId, elem.querySelector('.events-log')]));
loggedEvents.forEach((loggedEvent) => {
const textElem = this.containerElems.get(loggedEvent.id);
// Check if the element exists, the event list might contain events for containers that are
// not contained in our list.
if (textElem) {
textElem.textContent = loggedEvent.message;
}
});
}
async showLoggedEvents(text) {
const loggedEvents = new Map();
this.#debug({ text });
// Split text into logged-events and filter out empty lines.
const lines = text.split('\n').filter((line) => line);
// Reduce the list of events to the last of each container.
lines.forEach((line) => {
const loggedEvent = JSON.parse(line);
loggedEvents.set(loggedEvent.id, loggedEvent);
});
if (this.overlayElem && this.overlayElem.checkVisibility()) {
this.showLoggedEventsInOverlay(loggedEvents);
} else {
this.showLoggedEventsInContainerList(loggedEvents);
}
}
fetchAndShow(args = { forceReloading: false}) {
if (args.forceReloading) {
this.etag = '';
}
this.#debug('Fetching logged events from server');
fetch('/api/events/containers', {
cache: 'no-cache',
headers: {
'If-None-Match': this.etag,
},
})
.then((response) => this.storeEtag(response))
.then((response) => this.getTextFromResponse(response))
.then((text) => this.showLoggedEvents(text))
.catch((error) => {
if (error instanceof Error) {
throw error;
}
});
};
}
document.addEventListener('DOMContentLoaded', () => {
window.containerEventsLogClient = new ContainerEventsLogClient();
});