diff --git a/pages/services.tsx b/pages/services.tsx
index b906318..383272e 100644
--- a/pages/services.tsx
+++ b/pages/services.tsx
@@ -1,32 +1,28 @@
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 { Service, ServiceStatus, ServiceType, ServiceLocation } from '../interfaces/LinkTypes';
import Dockerode from 'dockerode';
-import { ReactElement, useEffect, useState } from 'react'
-import useSWR, { KeyedMutator } from 'swr';
+import { ReactElement } from 'react'
+import useSWR from 'swr';
const fetcher = (url: string) => fetch(url).then((res) => res.json())
//function Services(props: EntryList) {
-const Services = () => {
- const { serviceList, isLoading, isError } = useServices();
+function Services() {
+ const { initialData, fullData, loadingInitial, loadingFull, error } = useServices();
+
let content: ReactElement = <>>;
- // TODO: look into asyncing this as well
- useStatus(serviceList);
-
- if (isError) {
- content =
Error Loading data
+ if (error) { content = Error loading data
}
+ else if (loadingInitial) {
+ content = Loading
}
- else if (isLoading) {
- content = Loading..
- }
- else if (serviceList) {
+ else if (loadingFull) {
content =
}
+ else if (fullData) {
+ content =
+
+ }
+ else {
+ content = Error loading data
+ }
+
return (
<>
@@ -60,96 +75,121 @@ const Services = () => {
)
}
-function useStatus(serviceList: Service[] | undefined) {
- const { data, error } = useSWR('/api/containers', fetcher);
+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
- 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
+ // Location BRR7-4800U
if (entry.location === ServiceLocation.brr7_4800u) {
- // app in this context means any non-docker page
+ // Type APP
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;
+ 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.log(error);
+ .catch((error) => {
+ console.error("Error pinging Website: ", 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((container: Dockerode.ContainerInfo) => {
- console.log(container)
- if (container.Names.includes("/" + entry.docker_container_name) || container.Names.includes(entry.docker_container_name)) {
- if (container.State === "running") {
- entry.status = ServiceStatus.online;
+ // Type Docker
+ else if (entry.type === ServiceType.docker) {
+ containers.forEach((container) => {
+ // Docker API returns container names with / prepended, not sure whether this always happens so both cases are checked
+ if (container.Names.includes( entry.docker_container_name || "/" + 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) {
+ 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;
}
- }
- if (entry.docker_container_name == null) {
- console.log("MISSING DOCKER CONTAINER NAME FOR " + entry.name);
+ })
+ .catch((error) => {
+ console.error("Error pinging Website: ", error);
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;
- });
+ // If no Location matches
+ else {
+ console.warn("Service Location for Service " + entry.name + " not specified");
+ entry.status = ServiceStatus.error;
}
- else { entry.status = ServiceStatus.error }
- return;
+ 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
\ No newline at end of file