diff --git a/pages/api/containers.tsx b/pages/api/containers.tsx
new file mode 100644
index 0000000..44803a2
--- /dev/null
+++ b/pages/api/containers.tsx
@@ -0,0 +1,22 @@
+import fsPromises from 'fs/promises'
+import path from 'path'
+import { Service, ServiceStatus } from '../../interfaces/LinkTypes';
+
+export default async function ServicesAPI(req: any, res: any) {
+ try {
+ var Docker = require('dockerode');
+
+ const options = {
+ socketPath: '/var/run/docker.sock',
+ path: '/v1.41/containers/json'
+ };
+ var docker = new Docker({ socketPath: options.socketPath });
+ const list = await docker.listContainers({ all: true })
+
+ res.status(200).json(list);
+ }
+ catch (error) {
+ console.log(error);
+ res.status(500).json({ error: 'Error reading data' });
+ }
+}
\ No newline at end of file
diff --git a/pages/api/services.tsx b/pages/api/services.tsx
new file mode 100644
index 0000000..a416716
--- /dev/null
+++ b/pages/api/services.tsx
@@ -0,0 +1,21 @@
+import fsPromises from 'fs/promises'
+import path from 'path'
+import { Service, ServiceStatus } from '../../interfaces/LinkTypes';
+
+export default async function ServicesAPI(req: any, res: any) {
+ try {
+ const filePath = path.join(process.cwd(), '/public/pages.json')
+ const data = await fsPromises.readFile(filePath)
+ .then((file) => JSON.parse(file.toString()));
+ data.services.forEach((service: Service) => {
+ service.status = ServiceStatus.loading;
+ });
+
+ res.status(200).json(data.services);
+ }
+ catch (error) {
+ console.log(error);
+ res.status(500).json({ error: 'Error reading data' });
+ }
+}
+
diff --git a/pages/services.tsx b/pages/services.tsx
index 2ce661c..251be44 100644
--- a/pages/services.tsx
+++ b/pages/services.tsx
@@ -1,20 +1,50 @@
import Head from 'next/head'
import Link from 'next/link'
import styles from '/styles/Home.module.css'
-import fsPromises from 'fs/promises'
-import path, { resolve } from 'path'
-import type { CustomLink, LinkList } from '../interfaces/LinkTypes'
+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: LinkList) {
- const serviceList = props.services
+//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 =
Error Loading data
+ }
+ else if (isLoading) {
+ content = Loading..
+ }
+ else if (serviceList) {
+ content =
+
+ }
return (
<>
Neshura Servers
+
@@ -24,116 +54,101 @@ function Services(props: LinkList) {
Lists all available Services, most likely up-to-date
-
+
+ {content}
>
)
}
-// Gets a List of all services specified in /public/pages.json
-export async function getServerSideProps() {
- const filePath = path.join(process.cwd(), '/public/pages.json')
- // TODO: look into asyncing this API call
- const jsonData = await fsPromises.readFile(filePath)
- const list = JSON.parse(jsonData.toString())
- for (let index = 0; index < list.services.length; index++) {
- // TODO: look into asyncing this as well
- await status(list.services[index]);
+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);
}
- return { props: list }
}
-// reversing this to loop over given entries for every found container would probably improve latency
-async function status(entry: CustomLink) {
+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 === "brr7-4800u") {
+ if (entry.location === ServiceLocation.brr7_4800u) {
// app in this context means any non-docker page
- if (entry.type === "app") {
-
- let data = new Response();
- try {
- await fetch(entry.href).then((response: Response) => data = response);
- }
- catch (e) {
- console.log(e)
- return (entry.status = "Offline");
- }
-
- if (data.ok) {
- if (data.status == 200 || data.status == 301 || data.status == 302) {
- return (entry.status = "Online");
- }
- else return (entry.status = "Offline");
- }
- else return (entry.status = "Offline");
+ 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") {
- var Docker = require('dockerode');
-
- // TODO: read these paths from some config instead of hardcoding them
- const options = {
- socketPath: '/var/run/docker.sock',
- path: '/v1.41/containers/json'
- };
- var docker = new Docker({ socketPath: options.socketPath });
-
- // default is set as Offline, prevents uncaught cases without set status
- entry.status = "Offline";
- // TODO: async possible?
- await docker.listContainers({all: true}).then(
- ((containers: Dockerode.ContainerInfo[]) => {
- // 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 = "Online";
- }
- });
- if (entry.docker_container_name == null) {
- console.log("MISSING DOCKER CONTAINER NAME FOR " + entry.name);
- entry.status = "ERROR";
- }
- });
- })
- );
+ 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 = "ERROR" }
- return;
+ else { entry.status = ServiceStatus.error }
}
// for non-local locations pinging can be used to see if they're up
- else if (entry.location != "") {
- let data: Response;
- try {
- data = await fetch(entry.href);
- }
- catch (e) {
- console.log(e)
- return (entry.status = "Offline");
- }
-
- if (data.ok) {
- if (data.status == 200 || data.status == 301 || data.status == 302) {
- return (entry.status = "Online");
- }
- else return (entry.status = "Offline");
- }
- else return (entry.status = "Offline");
+ 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 { return (entry.status = "ERROR") }
+ else { entry.status = ServiceStatus.error }
+ return;
}
export default Services
\ No newline at end of file