remove not needded files

This commit is contained in:
CyberL1 2025-01-16 12:46:25 +01:00
parent d7dcabc3da
commit 81bf5fb6af
50 changed files with 4089 additions and 6175 deletions

View File

@ -1,4 +0,0 @@
PORT=3000
HOST="0.0.0.0"
PROXY_DOMAIN="localhost"

24
.gitignore vendored
View File

@ -1,2 +1,24 @@
.env # Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -1,5 +0,0 @@
FROM node:alpine
COPY . .
RUN npm i
ENTRYPOINT ["npm", "start"]

View File

@ -1,16 +1,13 @@
{ {
"$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": { "linter": {
"enabled": true,
"rules": { "rules": {
"recommended": false, "recommended": false,
"complexity": { "complexity": {
"noBannedTypes": "error",
"noExtraBooleanCast": "error", "noExtraBooleanCast": "error",
"noMultipleSpacesInRegularExpressionLiterals": "error", "noMultipleSpacesInRegularExpressionLiterals": "error",
"noUselessCatch": "error", "noUselessCatch": "error",
"noUselessTypeConstraint": "error",
"noWith": "error" "noWith": "error"
}, },
"correctness": { "correctness": {
@ -34,16 +31,14 @@
"noUnsafeOptionalChaining": "error", "noUnsafeOptionalChaining": "error",
"noUnusedLabels": "error", "noUnusedLabels": "error",
"noUnusedVariables": "error", "noUnusedVariables": "error",
"useArrayLiterals": "off",
"useExhaustiveDependencies": "warn",
"useHookAtTopLevel": "error",
"useIsNan": "error", "useIsNan": "error",
"useValidForDirection": "error", "useValidForDirection": "error",
"useYield": "error" "useYield": "error"
}, },
"style": { "style": { "noNamespace": "error", "useAsConstAssertion": "error" },
"noVar": "error",
"useBlockStatements": "error",
"useCollapsedElseIf": "error",
"useConst": "error"
},
"suspicious": { "suspicious": {
"noAsyncPromiseExecutor": "error", "noAsyncPromiseExecutor": "error",
"noCatchAssign": "error", "noCatchAssign": "error",
@ -56,22 +51,24 @@
"noDuplicateObjectKeys": "error", "noDuplicateObjectKeys": "error",
"noDuplicateParameters": "error", "noDuplicateParameters": "error",
"noEmptyBlockStatements": "error", "noEmptyBlockStatements": "error",
"noExplicitAny": "error",
"noExtraNonNullAssertion": "error",
"noFallthroughSwitchClause": "error", "noFallthroughSwitchClause": "error",
"noFunctionAssign": "error", "noFunctionAssign": "error",
"noGlobalAssign": "error", "noGlobalAssign": "error",
"noImportAssign": "error", "noImportAssign": "error",
"noMisleadingCharacterClass": "error", "noMisleadingCharacterClass": "error",
"noMisleadingInstantiator": "error",
"noPrototypeBuiltins": "error", "noPrototypeBuiltins": "error",
"noRedeclare": "error", "noRedeclare": "error",
"noShadowRestrictedNames": "error", "noShadowRestrictedNames": "error",
"noSparseArray": "error",
"noUnsafeDeclarationMerging": "error",
"noUnsafeNegation": "error", "noUnsafeNegation": "error",
"useGetterReturn": "error", "useGetterReturn": "error",
"useValidTypeof": "error" "useValidTypeof": "error"
} }
}
}, },
"formatter": { "ignore": ["**/dist"]
"indentStyle": "space",
"indentWidth": 2
} }
} }

View File

@ -1,22 +0,0 @@
name: code-containers
services:
server:
build: ..
env_file: ../.env
ports:
- 3000:3000
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
proxy:
build: ../proxy
env_file: ../.env
ports:
- 80:80
network_mode: host
frontend:
image: nginx:alpine
ports:
- 5173:80
volumes:
- ../frontend/dist:/usr/share/nginx/html

24
frontend/.gitignore vendored
View File

@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -1,74 +0,0 @@
{
"linter": {
"rules": {
"recommended": false,
"complexity": {
"noBannedTypes": "error",
"noExtraBooleanCast": "error",
"noMultipleSpacesInRegularExpressionLiterals": "error",
"noUselessCatch": "error",
"noUselessTypeConstraint": "error",
"noWith": "error"
},
"correctness": {
"noConstAssign": "error",
"noConstantCondition": "error",
"noEmptyCharacterClassInRegex": "error",
"noEmptyPattern": "error",
"noGlobalObjectCalls": "error",
"noInnerDeclarations": "error",
"noInvalidConstructorSuper": "error",
"noNewSymbol": "error",
"noNonoctalDecimalEscape": "error",
"noPrecisionLoss": "error",
"noSelfAssign": "error",
"noSetterReturn": "error",
"noSwitchDeclarations": "error",
"noUndeclaredVariables": "error",
"noUnreachable": "error",
"noUnreachableSuper": "error",
"noUnsafeFinally": "error",
"noUnsafeOptionalChaining": "error",
"noUnusedLabels": "error",
"noUnusedVariables": "error",
"useArrayLiterals": "off",
"useExhaustiveDependencies": "warn",
"useHookAtTopLevel": "error",
"useIsNan": "error",
"useValidForDirection": "error",
"useYield": "error"
},
"style": { "noNamespace": "error", "useAsConstAssertion": "error" },
"suspicious": {
"noAsyncPromiseExecutor": "error",
"noCatchAssign": "error",
"noClassAssign": "error",
"noCompareNegZero": "error",
"noControlCharactersInRegex": "error",
"noDebugger": "error",
"noDuplicateCase": "error",
"noDuplicateClassMembers": "error",
"noDuplicateObjectKeys": "error",
"noDuplicateParameters": "error",
"noEmptyBlockStatements": "error",
"noExplicitAny": "error",
"noExtraNonNullAssertion": "error",
"noFallthroughSwitchClause": "error",
"noFunctionAssign": "error",
"noGlobalAssign": "error",
"noImportAssign": "error",
"noMisleadingCharacterClass": "error",
"noMisleadingInstantiator": "error",
"noPrototypeBuiltins": "error",
"noRedeclare": "error",
"noShadowRestrictedNames": "error",
"noSparseArray": "error",
"noUnsafeDeclarationMerging": "error",
"noUnsafeNegation": "error",
"useGetterReturn": "error",
"useValidTypeof": "error"
}
},
"ignore": ["**/dist"]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
{
"name": "notifier-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@fontsource/roboto": "^5.1.0",
"@mui/icons-material": "^6.1.8",
"@mui/lab": "^6.0.0-beta.23",
"@mui/material": "^6.1.8",
"@xterm/addon-attach": "^0.11.0",
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^7.0.1"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@types/dockerode": "^3.3.34",
"@types/node": "^22.9.3",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.2.2",
"vite": "^5.2.0"
}
}

View File

@ -1,16 +0,0 @@
{
"compilerOptions": {
"module": "ESNext",
"target": "ES2024",
"lib": [
"ES2024"
],
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"paths": {
"#src/*": [
"./src/*"
]
}
}
}

4822
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,38 @@
{ {
"name": "code-containers", "name": "notifier-frontend",
"version": "1.0.0", "private": true,
"main": "src/index.ts", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"start": "node --experimental-strip-types .", "dev": "vite",
"dev": "node --experimental-strip-types --watch ." "build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
}, },
"imports": {
"#src/*": "./src/*"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": { "dependencies": {
"@fastify/websocket": "^11.0.2", "@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@fontsource/roboto": "^5.1.0",
"@mui/icons-material": "^6.1.8",
"@mui/lab": "^6.0.0-beta.23",
"@mui/material": "^6.1.8",
"@xterm/addon-attach": "^0.11.0",
"@xterm/addon-fit": "^0.10.0", "@xterm/addon-fit": "^0.10.0",
"dockerode": "^4.0.3", "@xterm/xterm": "^5.5.0",
"dotenv": "^16.4.7", "react": "^18.2.0",
"fastify": "^5.2.1" "react-dom": "^18.2.0",
"react-router": "^7.0.1"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^1.9.4" "@biomejs/biome": "^1.9.4",
"@types/dockerode": "^3.3.34",
"@types/node": "^22.9.3",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.2.2",
"vite": "^5.2.0"
} }
} }

View File

@ -1,8 +0,0 @@
FROM openresty/openresty:alpine
RUN wget -O /usr/local/openresty/lualib/resty/http.lua https://github.com/ledgetech/lua-resty-http/raw/refs/heads/master/lib/resty/http.lua
RUN wget -O /usr/local/openresty/lualib/resty/http_connect.lua https://github.com/ledgetech/lua-resty-http/raw/refs/heads/master/lib/resty/http_connect.lua
RUN wget -O /usr/local/openresty/lualib/resty/http_headers.lua https://github.com/ledgetech/lua-resty-http/raw/refs/heads/master/lib/resty/http_headers.lua
COPY proxy.conf etc/nginx/conf.d/proxy.conf
ENTRYPOINT ["/bin/sh", "-c", "sed -i \"s/{PROXY_DOMAIN}/$PROXY_DOMAIN/\" etc/nginx/conf.d/proxy.conf && nginx -g 'daemon off;'"]

View File

@ -1,40 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name {PROXY_DOMAIN};
location / {
proxy_pass http://127.0.0.1:5173;
}
location /api/ {
proxy_pass http://127.0.0.1:3000/;
}
}
server {
listen 80;
listen [::]:80;
server_name "~^(port-(?<port>.+)\.)?(?<container>.*)\.{PROXY_DOMAIN}";
location / {
if ($port = "") {
set $port "80";
}
set $ip '';
rewrite_by_lua_block {
local http = require("resty.http").new()
local res = http:request_uri("http://127.0.0.1:3000/containers/" .. ngx.var.container .. "/ip")
ngx.var.ip = res.body
}
proxy_pass http://$ip:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,35 +0,0 @@
import fastifyWebsocket from "@fastify/websocket";
import "dotenv/config";
import fastify from "fastify";
import { readdirSync } from "fs";
const app = fastify();
app.register(fastifyWebsocket);
const routes = readdirSync(`${import.meta.dirname}/routes`, {
recursive: true,
});
for (let file of routes) {
if (typeof file === "string") {
if (!file.endsWith(".ts")) {
continue;
}
file = file.replaceAll("\\", "/");
let route = `/${file.split(".").slice(0, -1).join(".")}`;
route = route.replaceAll("_", ":");
const routePath = route.endsWith("/index") ? route.slice(0, -6) : route;
console.log(`Loading route: ${routePath}`);
app.register((await import(`./routes/${file}`)).default, {
prefix: routePath,
});
}
}
await app.listen({ port: Number(process.env.PORT), host: process.env.HOST });
console.log("App ready on", `http://${process.env.HOST}:${process.env.PORT}`);

View File

@ -1,29 +0,0 @@
import type {
Container,
RemoveContainerParams,
RemoveContainerQuery,
} from "#src/types/Container.ts";
import { getContainer, getContainerResponse } from "#src/utils/containers.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.get("/", (req: FastifyRequest<{ Params: Container }>) => {
const container = getContainer(req.params.id);
return getContainerResponse(container);
});
fastify.delete(
"/",
async (
req: FastifyRequest<{
Params: RemoveContainerParams;
Querystring: RemoveContainerQuery;
}>,
) => {
const container = getContainer(req.params.id);
await container.remove({ force: req.query.force === "true" });
return getContainerResponse(container);
},
);
};

View File

@ -1,12 +0,0 @@
import type { Container } from "#src/types/Container.ts";
import { getContainer } from "#src/utils/containers.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.get("/", async (req: FastifyRequest<{ Params: Container }>) => {
const container = getContainer(req.params.id);
const { NetworkSettings } = await container.inspect();
return NetworkSettings.IPAddress;
});
};

View File

@ -1,45 +0,0 @@
import type {
CreateContainerBody,
RemoveContainerParams,
RemoveContainerQuery,
} from "#src/types/Container.ts";
import {
createContainer,
getContainer,
getContainerResponse,
} from "#src/utils/containers.ts";
import { getImage } from "#src/utils/images.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.post(
"/",
async (
req: FastifyRequest<{
Params: RemoveContainerParams;
Querystring: RemoveContainerQuery;
Body: CreateContainerBody;
}>,
) => {
if (req.body) {
if (!(await getImage(req.body?.image).inspect()).Id) {
return;
}
}
const oldContainer = getContainer(req.params.id);
const name = (await oldContainer.inspect()).Name;
const image =
req.body?.image ||
(await oldContainer.inspect()).Config.Labels["code-containers.image"];
await oldContainer.remove({ force: req.query.force === "true" });
const newContainer = await createContainer({ name, image });
await newContainer.start();
return getContainerResponse(newContainer);
},
);
};

View File

@ -1,12 +0,0 @@
import type { Container } from "#src/types/Container.ts";
import { getContainer, getContainerResponse } from "#src/utils/containers.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.put("/", async (req: FastifyRequest<{ Params: Container }>) => {
const container = getContainer(req.params.id);
await container.restart();
return getContainerResponse(container);
});
};

View File

@ -1,12 +0,0 @@
import type { Container } from "#src/types/Container.ts";
import { getContainer, getContainerResponse } from "#src/utils/containers.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.put("/", async (req: FastifyRequest<{ Params: Container }>) => {
const container = getContainer(req.params.id);
await container.start();
return getContainerResponse(container);
});
};

View File

@ -1,29 +0,0 @@
import type { Container } from "#src/types/Container.ts";
import { getContainer } from "#src/utils/containers.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.get(
"/",
async (req: FastifyRequest<{ Params: Container }>, reply) => {
const container = getContainer(req.params.id);
reply.header("Content-Type", "text/event-stream");
reply.header("Cache-Control", "no-cache");
reply.header("Connection", "keep-alive");
const stream = await container.stats({ stream: true });
if (!stream) {
reply.status(500).send("Error fetching stats");
return;
}
stream.on("data", (chunk) => {
reply.raw.write(`data: ${chunk.toString()}\n\n`);
});
stream.on("end", () => reply.raw.end());
return stream;
},
);
};

View File

@ -1,12 +0,0 @@
import type { Container } from "#src/types/Container.ts";
import { getContainer, getContainerResponse } from "#src/utils/containers.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.put("/", async (req: FastifyRequest<{ Params: Container }>) => {
const container = getContainer(req.params.id);
await container.stop();
return getContainerResponse(container);
});
};

View File

@ -1,52 +0,0 @@
import type { Container } from "#src/types/Container.ts";
import { getContainer } from "#src/utils/containers.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
import { PassThrough } from "stream";
export default (fastify: FastifyInstance) => {
fastify.get(
"/",
{ websocket: true },
async (connection, req: FastifyRequest<{ Params: Container }>) => {
const container = getContainer(req.params.id);
const exec = await container.exec({
Cmd: ["/bin/bash"],
AttachStdin: true,
AttachStdout: true,
AttachStderr: true,
Tty: true,
});
const stream = await exec.start({ hijack: true, stdin: true });
const stdout = new PassThrough();
const stderr = new PassThrough();
container.modem.demuxStream(stream, stdout, stderr);
connection.on("message", (data: Buffer) => {
console.log(new TextDecoder().decode(data));
if (new TextDecoder().decode(data).startsWith("{")) {
const parsed = JSON.parse(data.toString());
exec.resize({
h: parsed.rows,
w: parsed.cols,
});
} else {
stream.write(data);
}
});
stdout.on("data", (chunk) => {
connection.send(chunk.toString());
});
stderr.on("data", (chunk) => {
connection.send(chunk.toString());
});
},
);
};

View File

@ -1,39 +0,0 @@
import createContainerSchema from "#src/schemas/createContainerSchema.ts";
import type { CreateContainerBody, Container } from "#src/types/Container.ts";
import {
createContainer,
getContainerResponse,
getContainers,
} from "#src/utils/containers.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.get("/", async () => {
const containers = await getContainers();
const containersResponse = [];
for (const container of containers) {
const response = {
id: container.Id,
name: container.Names[0].slice(1),
image: container.Image,
status: container.State,
} as Omit<Container, "ip">;
containersResponse.push(response);
}
return containersResponse;
});
fastify.post(
"/",
{ schema: createContainerSchema },
async (req: FastifyRequest<{ Body: CreateContainerBody }>) => {
const container = await createContainer({ image: req.body.image });
await container.start();
return getContainerResponse(container);
},
);
};

View File

@ -1,10 +0,0 @@
import type { Image } from "#src/types/Image.ts";
import { getImage } from "#src/utils/images.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.get("/", (req: FastifyRequest<{ Params: Image }>) => {
const image = getImage(req.params.name);
return image.inspect();
});
};

View File

@ -1,8 +0,0 @@
import { getImages } from "#src/utils/images.ts";
import type { FastifyInstance, FastifyRequest } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.get("/", () => {
return getImages();
});
};

View File

@ -1,7 +0,0 @@
import type { FastifyInstance } from "fastify";
export default (fastify: FastifyInstance) => {
fastify.get("/", () => {
return { appName: "code-containers" };
});
};

View File

@ -1,13 +0,0 @@
import type { FastifySchema } from "fastify";
const createContainerSchema: FastifySchema = {
body: {
type: "object",
properties: {
image: { type: "string", minLength: 1 },
},
required: ["image"],
},
};
export default createContainerSchema;

View File

@ -1,20 +0,0 @@
export interface Container {
id: string;
name: string;
image: string;
status: string;
ip: string;
}
export interface CreateContainerBody {
name: string;
image: string;
}
export interface RemoveContainerParams {
id: string;
}
export interface RemoveContainerQuery {
force: string;
}

View File

@ -1,3 +0,0 @@
export interface Image {
name: string;
}

View File

@ -1,44 +0,0 @@
import type { Container, CreateContainerBody } from "#src/types/Container.ts";
import Dockerode from "dockerode";
const dockerode = new Dockerode();
export const getContainers = () => {
const containers = dockerode.listContainers({
filters: { label: ["code-containers.image"] },
all: true,
});
return containers;
};
export const getContainer = (id: string) => {
const container = dockerode.getContainer(id);
return container;
};
export const createContainer = ({ name, image }: CreateContainerBody) => {
const container = dockerode.createContainer({
name,
Image: `code-containers/${image}`,
Labels: {
"code-containers.image": image,
},
});
return container;
};
export const getContainerResponse = async (container: Dockerode.Container) => {
const inspect = await container.inspect();
const response = {
id: inspect.Id,
name: inspect.Name.slice(1),
image: inspect.Config.Image,
status: inspect.State.Status,
ip: inspect.NetworkSettings.Networks.bridge.IPAddress,
} as Container;
return response;
};

View File

@ -1,16 +0,0 @@
import Dockerode from "dockerode";
const dockerode = new Dockerode();
export const getImages = () => {
const images = dockerode.listImages({
filters: { reference: ["code-containers/*"] },
});
return images;
};
export const getImage = (name: string) => {
const image = dockerode.getImage(`code-containers/${name}`);
return image;
};