diff --git a/.gitignore b/.gitignore
index 67d0346..3751439 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,5 @@ yarn-error.log*
# production
/build/
/data/
-/confs/
\ No newline at end of file
+/confs/
+/private/
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index a90b352..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,45 +0,0 @@
-## INIT STEP
-# Install dependencies only when needed
-FROM node:18-alpine AS deps
-
-RUN apk add --no-cache libc6-compat
-WORKDIR /app
-
-# Copy the files needed to install deps
-COPY package.json yarn.lock ./
-RUN yarn install --frozen-lockfile
-
-## BUILD STEP
-# Rebuild the source code only when needed
-FROM node:18-alpine AS builder
-
-WORKDIR /app
-
-# Copy node_modules installed by the deps step
-COPY --from=deps /app/node_modules ./node_modules
-
-COPY . .
-
-RUN yarn build
-
-## RUN STEP
-FROM node:18-alpine AS runner
-
-LABEL author="neshura@proton.me"
-WORKDIR /usr/src/app
-
-ENV NODE_ENV production
-
-COPY --from=builder /app/public ./public
-COPY --from=builder /app/node_modules ./node_modules
-
-# Automatically leverage output traces to reduce image size
-# https://nextjs.org/docs/advanced-features/output-file-tracing
-COPY --from=builder /app/.next/standalone ./
-COPY --from=builder /app/.next/static ./.next/static
-
-# expose port 3000
-ENV PORT 3000
-EXPOSE 3000
-
-CMD [ "yarn", "start" ]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..844adaf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# Main Page Repository
+
+Release URL: [www.neshweb.net](https://www.neshweb.net)
+
+Development URL: [wip.neshweb.net](https://wip.neshweb.net)
diff --git a/components/layout.tsx b/components/layout.tsx
index 6a2f966..9205de4 100644
--- a/components/layout.tsx
+++ b/components/layout.tsx
@@ -48,24 +48,6 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
defer src='https://static.cloudflareinsights.com/beacon.min.js'
data-cf-beacon='{"token": "826fc083aa86417890c0ceb3e0a597fa"}'>
-
diff --git a/interfaces/CardTypes.ts b/interfaces/CardTypes.ts
index e2a9b74..21c5ec2 100644
--- a/interfaces/CardTypes.ts
+++ b/interfaces/CardTypes.ts
@@ -35,6 +35,7 @@ export enum Status {
export enum ServiceLocation {
brr7_4800u = "brr7-4800u",
+ tower_0 = "tower-0",
other = ""
}
diff --git a/interfaces/DockerStatus.ts b/interfaces/DockerStatus.ts
new file mode 100644
index 0000000..910f222
--- /dev/null
+++ b/interfaces/DockerStatus.ts
@@ -0,0 +1,11 @@
+import { ServiceLocation } from './CardTypes';
+export interface DockerInfo {
+ name: string,
+ status: DockerStatus,
+ id: string
+ location: ServiceLocation,
+}
+
+export enum DockerStatus {
+ running = "running",
+}
diff --git a/package.json b/package.json
index dbf4333..bc21cd6 100644
--- a/package.json
+++ b/package.json
@@ -3,10 +3,10 @@
"version": "0.2.0",
"private": true,
"scripts": {
- "dev:debug": "NODE_OPTIONS='--inspect' next dev -p 4040",
- "dev": "next dev -p 4040",
+ "dev:debug": "NODE_OPTIONS='--inspect' next dev -H :: -p 8001",
+ "dev": "next dev -H :: -p 8001",
"build": "next build",
- "start": "next start",
+ "start": "next start -H :: -p 8001",
"lint": "next lint"
},
"dependencies": {
diff --git a/pages/about.tsx b/pages/about.tsx
index 4874605..89768c9 100644
--- a/pages/about.tsx
+++ b/pages/about.tsx
@@ -14,7 +14,8 @@ export default function About() {
About
- This website is primarily for managing my game servers in one spot
+ I'm currently expanding what I want to do with this site.
+ Currently a list of available services and servers is available via the respective navbar entry.
>
)
diff --git a/pages/api/containers.tsx b/pages/api/containers.tsx
index 6f75e6e..7f6a6d2 100644
--- a/pages/api/containers.tsx
+++ b/pages/api/containers.tsx
@@ -1,13 +1,29 @@
import Docker from 'dockerode'
+import ApiSecret from '../../private/portainer_api_secret.json'
+import { DockerInfo } from '../../interfaces/DockerStatus';
+import { ServiceLocation } from '../../interfaces/CardTypes';
export default async function ContainersAPI(req: any, res: any) {
+ const token = JSON.parse(JSON.stringify(ApiSecret.token));
+
try {
- 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 })
+ const res1 = await fetch('https://portainer.neshweb.net/api/endpoints/2/docker/containers/json', {
+ method: "GET",
+ headers: {"X-API-Key": token}
+ });
+
+ const unparsed = await res1.json();
+ let list: DockerInfo[] = [];
+
+ unparsed.forEach((entry: any) => {
+ let newEntry = {} as DockerInfo;
+
+ newEntry.name = entry.Names[0].substring(1);
+ newEntry.status = entry.State;
+ newEntry.id = entry.Id;
+ newEntry.location = ServiceLocation.tower_0;
+ list.push(newEntry);
+ });
res.status(200).json(list);
}
diff --git a/pages/games.tsx b/pages/servers.tsx
similarity index 87%
rename from pages/games.tsx
rename to pages/servers.tsx
index f57ba1b..c193a49 100644
--- a/pages/games.tsx
+++ b/pages/servers.tsx
@@ -1,7 +1,7 @@
import Head from 'next/head'
import { Game } from '../interfaces/CardTypes';
import { PageContentBox, PageDescription, PageTitle, CardContentGame } from '../components/styles/content'
-import GameList from '../public/pages.json';
+import GameList from '../public/data/pages.json';
function Servers() {
// TODO: unuggly this shit
@@ -9,7 +9,7 @@ function Servers() {
return (
<>
- Neshweb - Games
+ Neshweb - Servers
diff --git a/pages/services.tsx b/pages/services.tsx
index 2ae5794..de5b066 100644
--- a/pages/services.tsx
+++ b/pages/services.tsx
@@ -3,10 +3,9 @@ import { Service, Status, ServiceType, ServiceLocation } from '../interfaces/Car
import Dockerode from 'dockerode';
import { ReactElement } from 'react'
import useSWR from 'swr';
-import { CardContentService, PageContentBoxNew as PageContentBox, PageDescription, PageTitle } from '../components/styles/content';
-import { ServiceCardMobile } from '../components/styles/cards/mobile';
-import ServiceList from '../public/pages.json';
-import useWindowSize from '../components/windowsize';
+import ServiceList from '../public/data/pages.json';
+import { DockerInfo } from '../interfaces/DockerStatus';
+import { CardContentService, PageContentBox, PageDescription, PageTitle } from '../components/styles/content';
const fetcher = (url: string) => fetch(url).then((res) => res.json())
@@ -79,82 +78,12 @@ function Services() {
)
}
-async function getStatus(entry: Service, containers: Dockerode.ContainerInfo[]) {
+async function getStatus(entry: Service, containers: DockerInfo[]) {
// 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 = Status.online;
- break;
- default:
- entry.status = Status.offline;
- }
- }
- else {
- entry.status = Status.offline;
- }
- })
- .catch((error) => {
- console.error("Error pinging Website: ", error);
- entry.status = Status.error;
- })
- }
- // Type Docker
- else if (entry.type === ServiceType.docker) {
- 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":
- entry.status = Status.online;
- break;
- default:
- console.log("Container Status " + container.State + " has no case implemented");
- entry.status = Status.offline;
- }
- found = true;
- // cancel the for
- break;
- }
- // If container name is not missing the container is set to offline
- else {
- entry.status = Status.offline;
- }
- }
- if (!found) {
- console.warn("Container for " + entry.name + " could not be found");
- }
- }
- // if name is null do not enter for loop
- else {
- console.error("Container Name not specified");
- entry.status = Status.error;
- }
- }
- // If no Type matches
- else {
- console.warn("Service Type for Service " + entry.name + " not specified or invalid");
- entry.status = Status.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
+ // Type APP
+ if (entry.type === ServiceType.app) {
await fetch(entry.href)
.then((response) => {
if (response.ok) {
@@ -177,15 +106,54 @@ async function getStatus(entry: Service, containers: Dockerode.ContainerInfo[])
entry.status = Status.error;
})
}
- // If no Location matches
+ // Type Docker
+ else if (entry.type === ServiceType.docker) {
+ 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 (container.name === entry.docker_container_name) {
+
+ if (container.location === entry.location) {
+ // so far only "running" is properly implemented, mroe cases to follow as needed
+ switch (container.status) {
+ case "running":
+ entry.status = Status.online;
+ break;
+ default:
+ console.log("Container Status " + container.status + " has no case implemented");
+ entry.status = Status.offline;
+ }
+ found = true;
+ // cancel the for
+ break;
+ }
+ }
+ // If container name is not missing the container is set to offline
+ else {
+ entry.status = Status.offline;
+ }
+ }
+ if (!found) {
+ console.warn("Container for " + entry.name + " could not be found");
+ }
+ }
+ // if name is null do not enter for loop
+ else {
+ console.error("Container Name not specified");
+ entry.status = Status.error;
+ }
+ }
+ // If no Type matches
else {
- console.warn("Service Location for Service " + entry.name + " not specified");
+ console.warn("Service Type for Service " + entry.name + " not specified or invalid");
entry.status = Status.error;
}
return entry;
}
-const fetchFullDataArray = (containerData: Dockerode.ContainerInfo[], dataSet: Service[]) => {
+const fetchFullDataArray = (containerData: DockerInfo[], dataSet: Service[]) => {
const fetchStatus = (entry: Service) => getStatus(entry, containerData);
return Promise.all(dataSet.map(fetchStatus));
}
@@ -207,4 +175,4 @@ function useServices() {
};
}
-export default Services
\ No newline at end of file
+export default Services
diff --git a/public/data/navbar.json b/public/data/navbar.json
index 613e960..cf2227b 100644
--- a/public/data/navbar.json
+++ b/public/data/navbar.json
@@ -9,8 +9,8 @@
"href": "/about"
},
{
- "name": "Games",
- "href": "/games"
+ "name": "Servers",
+ "href": "/servers"
},
{
"name": "Services",
diff --git a/public/pages.json b/public/data/pages.json
similarity index 75%
rename from public/pages.json
rename to public/data/pages.json
index 3ecb7f6..3ddbd0e 100644
--- a/public/pages.json
+++ b/public/data/pages.json
@@ -3,26 +3,39 @@
{
"name": "Nextcloud",
"icon": "/icons/nextcloud-logo.svg",
+<<<<<<< HEAD:public/pages.json
"href": "https://nextcloud.neshweb.net/",
"desc1": "Cloud Storage",
"desc": "Self-hosted Cloud Storage Service but longer and hopefully with wrap as well as some extra just to make sure",
+=======
+ "href": "https://nextcloud.neshweb.net",
+ "desc": "Self-hosted Cloud Storage Service",
+>>>>>>> main:public/data/pages.json
"warn": "Note: Registration requires approval",
"extLink": "https://qwant.com",
"extName": "Qwant",
"type": "docker",
"docker_container_name": "nextcloud",
- "location": "brr7-4800u"
+ "location": "tower-0"
},
{
+<<<<<<< HEAD:public/pages.json
"name": "Komga",
"icon": "/icons/komga-logo.png",
"href": "https://komga.neshweb.net/",
"desc1": "Manga/Comics",
"desc": "Self-hosted Comic Library",
"warn": "Note: Registration only via Admin",
+=======
+ "name": "Kavita",
+ "icon": "/icons/kavita-logo.svg",
+ "href": "https://kavita.neshweb.net",
+ "desc": "Self-hosted Manga Library",
+ "warn": "Registration via Admin invite",
+>>>>>>> main:public/data/pages.json
"type": "docker",
- "docker_container_name": "komga",
- "location": "brr7-4800u"
+ "docker_container_name": "kavita",
+ "location": "tower-0"
},
{
"name": "Calibre Web",
@@ -31,30 +44,50 @@
"desc1": "eBooks",
"desc": "Self-hosted Ebook Library Service",
"warn": "Note: Registration only via Admin",
- "type": "app",
- "location": "brr7-4800u"
+ "type": "docker",
+ "docker_container_name": "calibre-web",
+ "location": "tower-0"
},
{
"name": "PeerTube",
"icon": "/icons/peertube-logo.svg",
+<<<<<<< HEAD:public/pages.json
"href": "https://tube.neshweb.net/",
"desc1": "Video Platform",
+=======
+ "href": "https://tube.neshweb.net",
+>>>>>>> main:public/data/pages.json
"desc": "Self-hosted PeerTube Instance",
"warn": "Note: Registration only via Admin",
"type": "docker",
"docker_container_name": "peertube",
- "location": "brr7-4800u"
+ "location": "tower-0"
},
{
"name": "Mastodon",
"icon": "/icons/mastodon-logo.svg",
+<<<<<<< HEAD:public/pages.json
"href": "https://mastodon.neshweb.net/",
"desc1": "Twitter Alternative",
+=======
+ "href": "https://mastodon.neshweb.net",
+>>>>>>> main:public/data/pages.json
"desc": "Self-hosted Mastodon Instance",
"warn": "Note: Registration requires approval",
"type": "docker",
"docker_container_name": "mastodon-web",
- "location": "brr7-4800u"
+ "location": "tower-0"
+ },
+
+ {
+ "name": "Vaultwarden",
+ "icon": "/icons/vaultwarden-logo.svg",
+ "href": "https://vault.neshweb.net",
+ "desc": "Self-hosted Password Manager",
+ "warn": "Note: Invite only",
+ "type": "docker",
+ "docker_container_name": "vaultwarden",
+ "location": "tower-0"
},
{
"name": "File Browser",
@@ -64,7 +97,7 @@
"warn": "Note: Registration only via Admin",
"type": "docker",
"docker_container_name": "filebrowser",
- "location": "brr7-4800u"
+ "location": "tower-0"
},
{
"name": "Jellyfin",
@@ -75,7 +108,7 @@
"warn": "Note: Registration only via Admin",
"type": "docker",
"docker_container_name": "jellyfin",
- "location": "brr7-4800u"
+ "location": "tower-0"
},
{
"name": "Navidrome",
@@ -86,7 +119,7 @@
"warn": "Note: Registration only via Admin",
"type": "docker",
"docker_container_name": "navidrome",
- "location": "brr7-4800u"
+ "location": "tower-0"
},
{
"name": "Picard",
@@ -96,7 +129,7 @@
"warn": "Note: Access only via Admin",
"type": "docker",
"docker_container_name": "picard",
- "location": "brr7-4800u"
+ "location": "tower-0"
},
{
"name": "Gitlab",
@@ -107,7 +140,7 @@
"warn": "Note: Registration only via Admin",
"type": "docker",
"docker_container_name": "gitlab",
- "location": "brr7-4800u"
+ "location": "tower-0"
},
{
"name": "Portainer",
@@ -118,7 +151,7 @@
"warn": "Note: Admin Only",
"type": "docker",
"docker_container_name": "portainer",
- "location": "brr7-4800u"
+ "location": "tower-0"
},
{
"name": "Nginx",
@@ -129,6 +162,7 @@
"warn": "Note: Admin Only",
"type": "docker",
"docker_container_name": "nginx-prox",
+<<<<<<< HEAD:public/pages.json
"location": "brr7-4800u"
},
{
@@ -174,6 +208,18 @@
"type": "docker",
"docker_container_name": "Debug",
"location": "brr7-4800u"
+=======
+ "location": "tower-0"
+ },
+ {
+ "name": "Proxmox",
+ "icon": "/icons/proxmox-logo.png",
+ "href": "https://proxmox.neshweb.net/",
+ "desc": "Hypervisor Webinterface",
+ "warn": "Note: Admin Only",
+ "type": "app",
+ "location": ""
+>>>>>>> main:public/data/pages.json
}
],
"games": {
@@ -194,6 +240,14 @@
"icon": "/icons/zomboid-logo.png",
"ip": "91.13.248.30",
"status": "Online"
+ },
+ "factorio": {
+ "name": "Factorio",
+ "status": "Online"
+ },
+ "space_engineers": {
+ "name": "Space Engineers",
+ "status": "Online"
}
}
}