import Head from 'next/head' import Link from 'next/link' import styles from '/styles/Home.module.css' import { Service, ServiceStatus, ServiceType, ServiceLocation } from '../interfaces/LinkTypes'; import Dockerode from 'dockerode'; import { ReactElement } from 'react' import useSWR from 'swr'; const fetcher = (url: string) => fetch(url).then((res) => res.json()) //function Services(props: EntryList) { function Services() { const { initialData, fullData, loadingInitial, loadingFull, error } = useServices(); let content: ReactElement = <>; if (error) { content =
Error loading data
} else if (loadingInitial) { content =
Loading
} else if (loadingFull) { content =
{initialData?.map((item: Service) => (

{item.name}

{item.status}

{item.desc}

{item.warn}

))}
} else if (fullData) { content =
{fullData.map((item: Service) => (

{item.name}

{item.status}

{item.desc}

{item.warn}

))}
} else { content =
Error loading data
} 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 = ServiceStatus.online; break; default: entry.status = ServiceStatus.offline; } } else { entry.status = ServiceStatus.offline; } }) .catch((error) => { console.error("Error pinging Website: ", error); entry.status = ServiceStatus.error; }) } // Type Docker else if (entry.type === ServiceType.docker) { containers.forEach((container) => { // Docker API returns container names with / prepended if (container.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 = ServiceStatus.online; break; default: console.log("Container Status " + container.State + " has no case implemented"); entry.status = ServiceStatus.offline; } } // If container name is not missing the container is set to offline else if (entry.docker_container_name !== null) { // DEBUG console.log(entry.docker_container_name); console.log(container.Names); // DEBUG console.warn("Container for " + entry.name + " could not be found"); entry.status = ServiceStatus.offline; } else { console.error("Container Name not specified"); entry.status = ServiceStatus.error; } }) } // If no Type matches else { console.warn("Service Type for Service " + entry.name + " not specified or invalid"); entry.status = ServiceStatus.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 = ServiceStatus.online; break; default: entry.status = ServiceStatus.offline; } } else { entry.status = ServiceStatus.offline; } }) .catch((error) => { console.error("Error pinging Website: ", error); entry.status = ServiceStatus.error; }) } // If no Location matches else { console.warn("Service Location for Service " + entry.name + " not specified"); entry.status = ServiceStatus.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 console.log(fullError) // DEBUG return { initialData, fullData, loadingInitial, loadingFull, error: initialError || fullError || containerError, }; } export default Services