139 lines
4.5 KiB
TypeScript
139 lines
4.5 KiB
TypeScript
|
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 Dockerode from 'dockerode';
|
||
|
|
||
|
|
||
|
function Services(props: LinkList) {
|
||
|
const serviceList = props.services
|
||
|
return (
|
||
|
<>
|
||
|
<Head>
|
||
|
<title>Neshura Servers</title>
|
||
|
<meta charSet='utf-8' />
|
||
|
<link rel="icon" href="/favicon.ico" />
|
||
|
</Head>
|
||
|
|
||
|
<h1 className={styles.title}>
|
||
|
Service List
|
||
|
</h1>
|
||
|
|
||
|
<p className={styles.description}>
|
||
|
Lists all available Services, most likely up-to-date
|
||
|
</p>
|
||
|
<div className={styles.grid}>
|
||
|
{serviceList.map((item: CustomLink) => (
|
||
|
<Link key={item.name} href={item.href}>
|
||
|
<a className={styles.contentcard}>
|
||
|
<div className={styles.contenttitle}><h2>{item.name}</h2></div>
|
||
|
<div className={item.status == "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>
|
||
|
</>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// Gets a List of all services specified in /confs/pages.json
|
||
|
export async function getServerSideProps() {
|
||
|
const filePath = path.join(process.cwd(), './confs/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]);
|
||
|
}
|
||
|
return { props: list }
|
||
|
}
|
||
|
|
||
|
// reversing this to loop over given entries for every found container would probably improve latency
|
||
|
async function status(entry: CustomLink) {
|
||
|
// 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") {
|
||
|
// 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");
|
||
|
}
|
||
|
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";
|
||
|
}
|
||
|
});
|
||
|
})
|
||
|
);
|
||
|
}
|
||
|
else { entry.status = "ERROR" }
|
||
|
return;
|
||
|
}
|
||
|
// 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 { return (entry.status = "ERROR") }
|
||
|
}
|
||
|
|
||
|
export default Services
|