}
return (
<>
Neshura Servers
Service List
Lists all available Services, most likely up-to-date
{content}
>
)
}
async function getStatus(entry: Service, containers: Dockerode.ContainerInfo[]) {
// Currently the only location supporting different fetching depending on type is brr7-4800u
// Others to follow but low prio as this is currently the only location used
// Location BRR7-4800U
if (entry.location === ServiceLocation.brr7_4800u) {
// Type APP
if (entry.type === ServiceType.app) {
await fetch(entry.href)
.then((response) => {
if (response.ok) {
switch (response.status) {
case 200:
case 301:
case 302:
entry.status = Status.online;
break;
default:
entry.status = Status.offline;
}
}
else {
entry.status = Status.offline;
}
})
.catch((error) => {
console.error("Error pinging Website: ", error);
entry.status = Status.error;
})
}
// Type Docker
else if (entry.type === ServiceType.docker) {
if (entry.name !== null) {
let found = false;
for (let i = 0; i < containers.length; i++) {
const container = containers[i];
// Docker API returns container names with / prepended
if (containers[i].Names.includes("/" + entry.docker_container_name)) {
// so far only "running" is properly implemented, mroe cases to follow as needed
switch (container.State) {
case "running":
entry.status = Status.online;
break;
default:
console.log("Container Status " + container.State + " has no case implemented");
entry.status = Status.offline;
}
found = true;
// cancel the for
break;
}
// If container name is not missing the container is set to offline
else {
entry.status = Status.offline;
}
}
if (!found) {
console.warn("Container for " + entry.name + " could not be found");
}
}
// if name is null do not enter for loop
else {
console.error("Container Name not specified");
entry.status = Status.error;
}
}
// If no Type matches
else {
console.warn("Service Type for Service " + entry.name + " not specified or invalid");
entry.status = Status.error;
}
}
// Location Other
// TODO: implement docker type for other locations
else if (entry.location === ServiceLocation.other) {
// Currently uses the same handling as app type for the other location
await fetch(entry.href)
.then((response) => {
if (response.ok) {
switch (response.status) {
case 200:
case 301:
case 302:
entry.status = Status.online;
break;
default:
entry.status = Status.offline;
}
}
else {
entry.status = Status.offline;
}
})
.catch((error) => {
console.error("Error pinging Website: ", error);
entry.status = Status.error;
})
}
// If no Location matches
else {
console.warn("Service Location for Service " + entry.name + " not specified");
entry.status = Status.error;
}
return entry;
}
const fetchFullDataArray = (containerData: Dockerode.ContainerInfo[], dataSet: Service[]) => {
const fetchStatus = (entry: Service) => getStatus(entry, containerData);
return Promise.all(dataSet.map(fetchStatus));
}
function useServices() {
const { data: containerData, error: containerError } = useSWR('/api/containers', fetcher);
const { data: initialData, error: initialError } = useSWR('/api/services', fetcher);
const loadingInitial = !initialData && !initialError
const { data: fullData, error: fullError } = useSWR((initialData && containerData) ? [containerData, initialData] : null, fetchFullDataArray)
const loadingFull = !fullData && !fullError
return {
initialData,
fullData,
loadingInitial,
loadingFull,
error: initialError || fullError || containerError,
};
}
export default Services