6af8cb3e1b
Added 2 API Endpoints for use with useSWR, removed the service and status fetching from getStaticProps, rewrote status fetching to use async (WIP, needs testing)
154 lines
4.8 KiB
TypeScript
154 lines
4.8 KiB
TypeScript
import Head from 'next/head'
|
|
import Link from 'next/link'
|
|
import styles from '/styles/Home.module.css'
|
|
import { Service, CustomLink, EntryList, ServiceStatus, ServiceType, ServiceLocation } from '../interfaces/LinkTypes'
|
|
import Dockerode from 'dockerode';
|
|
import { ReactElement, useEffect, useState } from 'react'
|
|
import useSWR, { KeyedMutator } from 'swr';
|
|
|
|
const fetcher = (url: string) => fetch(url).then((res) => res.json())
|
|
|
|
//function Services(props: EntryList) {
|
|
const Services = () => {
|
|
const { serviceList, isLoading, isError } = useServices();
|
|
|
|
let content: ReactElement = <></>;
|
|
|
|
// TODO: look into asyncing this as well
|
|
useStatus(serviceList);
|
|
|
|
if (isError) {
|
|
content = <div className={styles.grid}>Error Loading data</div>
|
|
}
|
|
else if (isLoading) {
|
|
content = <div className={styles.grid}>Loading..</div>
|
|
}
|
|
else if (serviceList) {
|
|
content =
|
|
<div className={styles.grid}>
|
|
{serviceList.map((item: Service) => (
|
|
<Link key={item.name} href={item.href}>
|
|
<a className={styles.contentcard}>
|
|
<div className={styles.contenttitle}><h2>{item.name}</h2></div>
|
|
<div className={item.status === ServiceStatus.online ? styles.contentonline : styles.contentoffline}>{item.status}</div>
|
|
<div><p>{item.desc}</p></div>
|
|
<div className={styles.cardwarn}><p>{item.warn}</p></div>
|
|
</a>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
}
|
|
return (
|
|
<>
|
|
<Head>
|
|
<title>Neshura Servers</title>
|
|
<meta charSet='utf-8' />
|
|
<link rel="icon" href="/favicon.ico" />
|
|
<meta name="description" content="Lists all available Services, most likely up-to-date" />
|
|
</Head>
|
|
|
|
<h1 className={styles.title}>
|
|
Service List
|
|
</h1>
|
|
|
|
<p className={styles.description}>
|
|
Lists all available Services, most likely up-to-date
|
|
</p>
|
|
|
|
{content}
|
|
</>
|
|
)
|
|
}
|
|
|
|
function useStatus(serviceList: Service[] | undefined) {
|
|
const { data, error } = useSWR('/api/containers', fetcher);
|
|
|
|
if (data && serviceList) {
|
|
serviceList.forEach((service: Service) => {
|
|
getStatus(data, service);
|
|
})
|
|
}
|
|
else if (error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
function useServices(): { serviceList: Service[] | undefined, isLoading: boolean, isError: boolean } {
|
|
const { data, error } = useSWR('/api/services', fetcher);
|
|
|
|
return {
|
|
serviceList: data,
|
|
isLoading: !error && !data,
|
|
isError: error
|
|
};
|
|
}
|
|
|
|
function getStatus(containers: Dockerode.ContainerInfo[], entry: Service) {
|
|
// for now only the BRR7-4800U can be used with Docker, needs changing once more Servers are used
|
|
// TODO: support multiple locations for docker
|
|
if (entry.location === ServiceLocation.brr7_4800u) {
|
|
// app in this context means any non-docker page
|
|
if (entry.type === ServiceType.app) {
|
|
fetch(entry.href)
|
|
.then((data: Response) => {
|
|
if (data.ok) {
|
|
if (data.status == 200 || data.status == 301 || data.status == 302) {
|
|
entry.status = ServiceStatus.online;
|
|
}
|
|
else {
|
|
entry.status = ServiceStatus.offline;
|
|
}
|
|
}
|
|
else {
|
|
entry.status = ServiceStatus.offline;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.log(error);
|
|
entry.status = ServiceStatus.error;
|
|
});
|
|
}
|
|
else if (entry.type === "docker") {
|
|
entry.status = ServiceStatus.offline;
|
|
// Loop over every found container and compare to the entry provided
|
|
containers.forEach((element: Dockerode.ContainerInfo) => {
|
|
element.Names.forEach((containerName: string) => {
|
|
if (containerName.startsWith("/")) {
|
|
containerName = containerName.substring(1);
|
|
}
|
|
if (containerName === entry.docker_container_name) {
|
|
entry.status = ServiceStatus.online;
|
|
}
|
|
});
|
|
if (entry.docker_container_name == null) {
|
|
console.log("MISSING DOCKER CONTAINER NAME FOR " + entry.name);
|
|
entry.status = ServiceStatus.error;
|
|
}
|
|
});
|
|
}
|
|
else { entry.status = ServiceStatus.error }
|
|
}
|
|
// for non-local locations pinging can be used to see if they're up
|
|
else if (entry.location === ServiceLocation.other) {
|
|
fetch(entry.href)
|
|
.then((data) => {
|
|
if (data.ok) {
|
|
if (data.status == 200 || data.status == 301 || data.status == 302) {
|
|
return (entry.status = ServiceStatus.online);
|
|
}
|
|
else (entry.status = ServiceStatus.offline);
|
|
}
|
|
else {
|
|
entry.status = ServiceStatus.offline;
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
console.log(error);
|
|
entry.status = ServiceStatus.error;
|
|
});
|
|
}
|
|
else { entry.status = ServiceStatus.error }
|
|
return;
|
|
}
|
|
|
|
export default Services |