first public source commit

This commit is contained in:
Ben Phelps 2022-08-24 10:44:35 +03:00
parent 1a4fbb9d42
commit 3914fee775
65 changed files with 4697 additions and 312 deletions

18
src/pages/_app.js Normal file
View file

@ -0,0 +1,18 @@
import { SWRConfig } from "swr";
import "styles/globals.css";
import "styles/weather-icons.css";
function MyApp({ Component, pageProps }) {
return (
<SWRConfig
value={{
fetcher: (resource, init) =>
fetch(resource, init).then((res) => res.json()),
}}
>
<Component {...pageProps} />
</SWRConfig>
);
}
export default MyApp;

24
src/pages/_document.js Normal file
View file

@ -0,0 +1,24 @@
import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html>
<Head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin="true"
/>
<link
href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,300;0,400;0,500;0,600;1,300;1,400;1,500&display=swap"
rel="stylesheet"
/>
</Head>
<body className="w-full h-full bg-theme-50 dark:bg-theme-800 transition duration-150 ease-in-out">
<Main />
<NextScript />
</body>
</Html>
);
}

View file

@ -0,0 +1,27 @@
import { promises as fs } from "fs";
import path from "path";
import yaml from "js-yaml";
import checkAndCopyConfig from "utils/config";
export default async function handler(req, res) {
checkAndCopyConfig("bookmarks.yaml");
const bookmarksYaml = path.join(process.cwd(), "config", "bookmarks.yaml");
const fileContents = await fs.readFile(bookmarksYaml, "utf8");
const bookmarks = yaml.load(fileContents);
// map easy to write YAML objects into easy to consume JS arrays
const bookmarksArray = bookmarks.map((group) => {
return {
name: Object.keys(group)[0],
bookmarks: group[Object.keys(group)[0]].map((entries) => {
return {
name: Object.keys(entries)[0],
...entries[Object.keys(entries)[0]][0],
};
}),
};
});
res.send(bookmarksArray);
}

View file

@ -0,0 +1,49 @@
import Docker from "dockerode";
import getDockerArguments from "utils/docker";
export default async function handler(req, res) {
const { service } = req.query;
const [containerName, containerServer] = service;
if (!containerName && !containerServer) {
res.status(400).send({
error: "docker query parameters are required",
});
return;
}
try {
const docker = new Docker(await getDockerArguments(containerServer));
const containers = await docker.listContainers();
// bad docker connections can result in a <Buffer ...> object?
// in any case, this ensures the result is the expected array
if (!Array.isArray(containers)) {
return res.status(500).send({
error: "query failed",
});
}
const containerNames = containers.map((container) => {
return container.Names[0].replace(/^\//, "");
});
const containerExists = containerNames.includes(containerName);
if (!containerExists) {
return res.status(404).send({
error: "not found",
});
}
const container = docker.getContainer(containerName);
const stats = await container.stats({ stream: false });
return res.status(200).json({
stats: stats,
});
} catch {
return res.status(500).send({
error: "unknown error",
});
}
}

View file

@ -0,0 +1,48 @@
import Docker from "dockerode";
import getDockerArguments from "utils/docker";
export default async function handler(req, res) {
const { service } = req.query;
const [containerName, containerServer] = service;
if (!containerName && !containerServer) {
return res.status(400).send({
error: "docker query parameters are required",
});
}
try {
const docker = new Docker(await getDockerArguments(containerServer));
const containers = await docker.listContainers();
// bad docker connections can result in a <Buffer ...> object?
// in any case, this ensures the result is the expected array
if (!Array.isArray(containers)) {
return res.status(500).send({
error: "query failed",
});
}
const containerNames = containers.map((container) => {
return container.Names[0].replace(/^\//, "");
});
const containerExists = containerNames.includes(containerName);
if (!containerExists) {
return res.status(404).send({
error: "not found",
});
}
const container = docker.getContainer(containerName);
const info = await container.inspect();
return res.status(200).json({
status: info.State.Status,
});
} catch {
return res.status(500).send({
error: "unknown error",
});
}
}

29
src/pages/api/proxy.js Normal file
View file

@ -0,0 +1,29 @@
function pick(object, keys) {
return;
}
export default async function handler(req, res) {
const headers = ["X-API-Key", "Content-Type", "Authorization"].reduce((obj, key) => {
if (req.headers && req.headers.hasOwnProperty(key.toLowerCase())) {
obj[key] = req.headers[key.toLowerCase()];
}
return obj;
}, {});
try {
const result = await fetch(req.query.url, {
strictSSL: false,
rejectUnhauthorized: false,
method: req.method,
headers: headers,
body: req.method == "GET" || req.method == "HEAD" ? null : req.body,
}).then((res) => res);
const forward = await result.text();
return res.status(result.status).send(forward);
} catch {
return res.status(500).send({
error: "query failed",
});
}
}

View file

@ -0,0 +1,27 @@
import { promises as fs } from "fs";
import path from "path";
import yaml from "js-yaml";
import checkAndCopyConfig from "utils/config";
export default async function handler(req, res) {
checkAndCopyConfig("services.yaml");
const servicesYaml = path.join(process.cwd(), "config", "services.yaml");
const fileContents = await fs.readFile(servicesYaml, "utf8");
const services = yaml.load(fileContents);
// map easy to write YAML objects into easy to consume JS arrays
const servicesArray = services.map((group) => {
return {
name: Object.keys(group)[0],
services: group[Object.keys(group)[0]].map((entries) => {
return {
name: Object.keys(entries)[0],
...entries[Object.keys(entries)[0]],
};
}),
};
});
res.send(servicesArray);
}

View file

@ -0,0 +1,22 @@
import { promises as fs } from "fs";
import path from "path";
import yaml from "js-yaml";
import checkAndCopyConfig from "utils/config";
export default async function handler(req, res) {
checkAndCopyConfig("widgets.yaml");
const widgetsYaml = path.join(process.cwd(), "config", "widgets.yaml");
const fileContents = await fs.readFile(widgetsYaml, "utf8");
const widgets = yaml.load(fileContents);
// map easy to write YAML objects into easy to consume JS arrays
const widgetsArray = widgets.map((group) => {
return {
type: Object.keys(group)[0],
options: { ...group[Object.keys(group)[0]] },
};
});
res.send(widgetsArray);
}

View file

@ -0,0 +1,14 @@
import { cpu, drive, mem, netstat } from "node-os-utils";
export default async function handler(req, res) {
const { disk } = req.query;
res.send({
cpu: {
usage: await cpu.usage(),
load: cpu.loadavgTime(5),
},
drive: await drive.info(disk || "/"),
memory: await mem.info(),
});
}

View file

@ -0,0 +1,9 @@
import cachedFetch from "utils/cached-fetch";
export default async function handler(req, res) {
const { lat, lon, apiKey, duration } = req.query;
const api_url = `http://api.weatherapi.com/v1/current.json?q=${lat},${lon}&key=${apiKey}`;
res.send(await cachedFetch(api_url, duration));
}

58
src/pages/index.js Normal file
View file

@ -0,0 +1,58 @@
import useSWR from "swr";
import Head from "next/head";
import dynamic from "next/dynamic";
import { ThemeProvider } from "utils/theme-context";
import ServicesGroup from "components/services/group";
import BookmarksGroup from "components/bookmarks/group";
import Widget from "components/widget";
const ThemeToggle = dynamic(() => import("components/theme-toggle"), {
ssr: false,
});
export default function Home() {
const { data: services, error: servicesError } = useSWR("/api/services");
const { data: bookmarks, error: bookmarksError } = useSWR("/api/bookmarks");
const { data: widgets, error: widgetsError } = useSWR("/api/widgets");
return (
<ThemeProvider>
<Head>
<title>Welcome</title>
</Head>
<div className="w-full container m-auto flex flex-col h-screen justify-between">
<div className="flex flex-wrap m-8 pb-4 mt-10 border-b-2 border-theme-800 dark:border-theme-200">
{widgets && (
<>
{widgets.map((widget) => (
<Widget key={widget.type} widget={widget} />
))}
</>
)}
</div>
{services && (
<div className="flex flex-wrap p-8 items-start">
{services.map((group) => (
<ServicesGroup key={group.name} services={group} />
))}
</div>
)}
{bookmarks && (
<div className="grow flex flex-wrap pt-0 p-8">
{bookmarks.map((group) => (
<BookmarksGroup key={group.name} group={group} />
))}
</div>
)}
<div className="rounded-full flex p-8 w-full justify-end">
<ThemeToggle />
</div>
</div>
</ThemeProvider>
);
}