2022-12-03 20:02:13 +00:00
|
|
|
import Head from 'next/head'
|
2022-12-17 00:20:58 +00:00
|
|
|
import { Service, Status, ServiceType, ServiceLocation } from '../interfaces/CardTypes';
|
2022-12-03 20:02:13 +00:00
|
|
|
import Dockerode from 'dockerode';
|
2022-12-11 15:30:11 +00:00
|
|
|
import { ReactElement } from 'react'
|
|
|
|
import useSWR from 'swr';
|
2022-12-17 23:38:37 +00:00
|
|
|
import { CardContentService, PageContentBox, PageDescription, PageTitle } from '../components/styles/content';
|
|
|
|
import ServiceList from '../public/pages.json';
|
2022-12-03 20:02:13 +00:00
|
|
|
|
2022-12-10 02:02:03 +00:00
|
|
|
const fetcher = (url: string) => fetch(url).then((res) => res.json())
|
2022-12-03 20:02:13 +00:00
|
|
|
|
2022-12-11 15:30:11 +00:00
|
|
|
function Services() {
|
2022-12-17 23:38:37 +00:00
|
|
|
const { initialData, fullData, loadingFull, error } = useServices();
|
2022-12-10 02:02:03 +00:00
|
|
|
|
2022-12-11 15:30:11 +00:00
|
|
|
let content: ReactElement = <></>;
|
2022-12-10 02:02:03 +00:00
|
|
|
|
2022-12-11 15:30:11 +00:00
|
|
|
if (error) { content = <div>Error loading data</div> }
|
|
|
|
else if (loadingFull) {
|
|
|
|
content =
|
2022-12-15 23:11:30 +00:00
|
|
|
<PageContentBox>
|
2022-12-11 15:30:11 +00:00
|
|
|
{initialData?.map((item: Service) => (
|
2022-12-17 00:20:58 +00:00
|
|
|
<CardContentService key={item.name} content={item} />
|
2022-12-11 15:30:11 +00:00
|
|
|
))}
|
2022-12-15 23:11:30 +00:00
|
|
|
</PageContentBox>
|
2022-12-10 02:02:03 +00:00
|
|
|
}
|
2022-12-11 15:30:11 +00:00
|
|
|
else if (fullData) {
|
2022-12-10 02:02:03 +00:00
|
|
|
content =
|
2022-12-15 23:11:30 +00:00
|
|
|
<PageContentBox>
|
2022-12-11 15:30:11 +00:00
|
|
|
{fullData.map((item: Service) => (
|
2022-12-17 00:20:58 +00:00
|
|
|
<CardContentService key={item.name} content={item} />
|
2022-12-10 02:02:03 +00:00
|
|
|
))}
|
2022-12-15 23:11:30 +00:00
|
|
|
</PageContentBox>
|
2022-12-10 02:02:03 +00:00
|
|
|
}
|
2022-12-11 15:30:11 +00:00
|
|
|
else {
|
|
|
|
content = <div>Error loading data</div>
|
|
|
|
}
|
|
|
|
|
2022-12-03 20:02:13 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<Head>
|
|
|
|
<title>Neshura Servers</title>
|
|
|
|
<meta charSet='utf-8' />
|
|
|
|
<link rel="icon" href="/favicon.ico" />
|
2022-12-10 02:02:03 +00:00
|
|
|
<meta name="description" content="Lists all available Services, most likely up-to-date" />
|
2022-12-03 20:02:13 +00:00
|
|
|
</Head>
|
|
|
|
|
2022-12-15 23:11:30 +00:00
|
|
|
<PageTitle>
|
2022-12-03 20:02:13 +00:00
|
|
|
Service List
|
2022-12-15 23:11:30 +00:00
|
|
|
</PageTitle>
|
2022-12-03 20:02:13 +00:00
|
|
|
|
2022-12-15 23:11:30 +00:00
|
|
|
<PageDescription>
|
2022-12-03 20:02:13 +00:00
|
|
|
Lists all available Services, most likely up-to-date
|
2022-12-15 23:11:30 +00:00
|
|
|
</PageDescription>
|
2022-12-10 02:02:03 +00:00
|
|
|
|
|
|
|
{content}
|
2022-12-03 20:02:13 +00:00
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-12-11 15:30:11 +00:00
|
|
|
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
|
2022-12-10 02:02:03 +00:00
|
|
|
|
2022-12-11 15:30:11 +00:00
|
|
|
// Location BRR7-4800U
|
2022-12-10 02:02:03 +00:00
|
|
|
if (entry.location === ServiceLocation.brr7_4800u) {
|
2022-12-11 15:30:11 +00:00
|
|
|
// Type APP
|
2022-12-10 02:02:03 +00:00
|
|
|
if (entry.type === ServiceType.app) {
|
2022-12-11 15:30:11 +00:00
|
|
|
await fetch(entry.href)
|
|
|
|
.then((response) => {
|
|
|
|
if (response.ok) {
|
2022-12-11 16:11:02 +00:00
|
|
|
switch (response.status) {
|
2022-12-11 15:30:11 +00:00
|
|
|
case 200:
|
|
|
|
case 301:
|
|
|
|
case 302:
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.online;
|
2022-12-11 15:30:11 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.offline;
|
2022-12-03 20:02:13 +00:00
|
|
|
}
|
2022-12-10 02:02:03 +00:00
|
|
|
}
|
|
|
|
else {
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.offline;
|
2022-12-10 02:02:03 +00:00
|
|
|
}
|
2022-12-03 20:02:13 +00:00
|
|
|
})
|
2022-12-11 15:30:11 +00:00
|
|
|
.catch((error) => {
|
|
|
|
console.error("Error pinging Website: ", error);
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.error;
|
2022-12-11 15:30:11 +00:00
|
|
|
})
|
2022-12-10 02:02:03 +00:00
|
|
|
}
|
2022-12-11 15:30:11 +00:00
|
|
|
// Type Docker
|
|
|
|
else if (entry.type === ServiceType.docker) {
|
2022-12-11 16:24:03 +00:00
|
|
|
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":
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.online;
|
2022-12-11 16:24:03 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.log("Container Status " + container.State + " has no case implemented");
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.offline;
|
2022-12-11 16:24:03 +00:00
|
|
|
}
|
|
|
|
found = true;
|
|
|
|
// cancel the for
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// If container name is not missing the container is set to offline
|
|
|
|
else {
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.offline;
|
2022-12-10 02:12:08 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-11 16:24:03 +00:00
|
|
|
if (!found) {
|
2022-12-11 15:30:11 +00:00
|
|
|
console.warn("Container for " + entry.name + " could not be found");
|
2022-12-10 02:02:03 +00:00
|
|
|
}
|
2022-12-11 16:11:02 +00:00
|
|
|
}
|
2022-12-11 16:24:03 +00:00
|
|
|
// if name is null do not enter for loop
|
|
|
|
else {
|
|
|
|
console.error("Container Name not specified");
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.error;
|
2022-12-11 16:24:03 +00:00
|
|
|
}
|
2022-12-11 15:30:11 +00:00
|
|
|
}
|
|
|
|
// If no Type matches
|
|
|
|
else {
|
|
|
|
console.warn("Service Type for Service " + entry.name + " not specified or invalid");
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.error;
|
2022-12-03 20:02:13 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-11 15:30:11 +00:00
|
|
|
// Location Other
|
|
|
|
// TODO: implement docker type for other locations
|
2022-12-10 02:02:03 +00:00
|
|
|
else if (entry.location === ServiceLocation.other) {
|
2022-12-11 15:30:11 +00:00
|
|
|
// Currently uses the same handling as app type for the other location
|
|
|
|
await fetch(entry.href)
|
2022-12-11 16:11:02 +00:00
|
|
|
.then((response) => {
|
|
|
|
if (response.ok) {
|
|
|
|
switch (response.status) {
|
|
|
|
case 200:
|
|
|
|
case 301:
|
|
|
|
case 302:
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.online;
|
2022-12-11 16:11:02 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.offline;
|
2022-12-11 15:30:11 +00:00
|
|
|
}
|
2022-12-11 16:11:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.offline;
|
2022-12-11 16:11:02 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
console.error("Error pinging Website: ", error);
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.error;
|
2022-12-11 16:11:02 +00:00
|
|
|
})
|
2022-12-11 15:30:11 +00:00
|
|
|
}
|
|
|
|
// If no Location matches
|
|
|
|
else {
|
|
|
|
console.warn("Service Location for Service " + entry.name + " not specified");
|
2022-12-17 00:20:58 +00:00
|
|
|
entry.status = Status.error;
|
2022-12-03 20:02:13 +00:00
|
|
|
}
|
2022-12-11 15:30:11 +00:00
|
|
|
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);
|
2022-12-17 23:38:37 +00:00
|
|
|
// TODO: unfuck this
|
|
|
|
const initialData: Service[] = JSON.parse(JSON.stringify(ServiceList.services));
|
|
|
|
initialData.forEach((service) => {
|
|
|
|
if (service.status === undefined) service.status = Status.loading;
|
|
|
|
})
|
|
|
|
const { data: fullData, error: fullError } = useSWR((containerData) ? [containerData, initialData] : null, fetchFullDataArray)
|
2022-12-11 15:30:11 +00:00
|
|
|
const loadingFull = !fullData && !fullError
|
|
|
|
return {
|
|
|
|
initialData,
|
|
|
|
fullData,
|
|
|
|
loadingFull,
|
2022-12-17 23:38:37 +00:00
|
|
|
error: fullError || containerError,
|
2022-12-11 15:30:11 +00:00
|
|
|
};
|
2022-12-03 20:02:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export default Services
|