mirror of
https://github.com/CyberL1/dlinux-dashboard.git
synced 2025-01-21 17:09:19 -05:00
remove not needded files
This commit is contained in:
parent
d7dcabc3da
commit
81bf5fb6af
@ -1,4 +0,0 @@
|
||||
PORT=3000
|
||||
HOST="0.0.0.0"
|
||||
|
||||
PROXY_DOMAIN="localhost"
|
24
.gitignore
vendored
24
.gitignore
vendored
@ -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
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
@ -1,5 +0,0 @@
|
||||
FROM node:alpine
|
||||
COPY . .
|
||||
|
||||
RUN npm i
|
||||
ENTRYPOINT ["npm", "start"]
|
27
biome.json
27
biome.json
@ -1,16 +1,13 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": false,
|
||||
"complexity": {
|
||||
"noBannedTypes": "error",
|
||||
"noExtraBooleanCast": "error",
|
||||
"noMultipleSpacesInRegularExpressionLiterals": "error",
|
||||
"noUselessCatch": "error",
|
||||
"noUselessTypeConstraint": "error",
|
||||
"noWith": "error"
|
||||
},
|
||||
"correctness": {
|
||||
@ -34,16 +31,14 @@
|
||||
"noUnsafeOptionalChaining": "error",
|
||||
"noUnusedLabels": "error",
|
||||
"noUnusedVariables": "error",
|
||||
"useArrayLiterals": "off",
|
||||
"useExhaustiveDependencies": "warn",
|
||||
"useHookAtTopLevel": "error",
|
||||
"useIsNan": "error",
|
||||
"useValidForDirection": "error",
|
||||
"useYield": "error"
|
||||
},
|
||||
"style": {
|
||||
"noVar": "error",
|
||||
"useBlockStatements": "error",
|
||||
"useCollapsedElseIf": "error",
|
||||
"useConst": "error"
|
||||
},
|
||||
"style": { "noNamespace": "error", "useAsConstAssertion": "error" },
|
||||
"suspicious": {
|
||||
"noAsyncPromiseExecutor": "error",
|
||||
"noCatchAssign": "error",
|
||||
@ -56,22 +51,24 @@
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"formatter": {
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2
|
||||
"ignore": ["**/dist"]
|
||||
}
|
||||
}
|
||||
|
@ -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
24
frontend/.gitignore
vendored
@ -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?
|
@ -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"]
|
||||
}
|
||||
}
|
4543
frontend/package-lock.json
generated
4543
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"target": "ES2024",
|
||||
"lib": [
|
||||
"ES2024"
|
||||
],
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"paths": {
|
||||
"#src/*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
4800
package-lock.json
generated
4800
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
45
package.json
45
package.json
@ -1,27 +1,38 @@
|
||||
{
|
||||
"name": "code-containers",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.ts",
|
||||
"name": "notifier-frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node --experimental-strip-types .",
|
||||
"dev": "node --experimental-strip-types --watch ."
|
||||
"dev": "vite",
|
||||
"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": {
|
||||
"@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",
|
||||
"dockerode": "^4.0.3",
|
||||
"dotenv": "^16.4.7",
|
||||
"fastify": "^5.2.1"
|
||||
"@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"
|
||||
"@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"
|
||||
}
|
||||
}
|
||||
|
@ -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;'"]
|
@ -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";
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
35
src/index.ts
35
src/index.ts
@ -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}`);
|
@ -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);
|
||||
},
|
||||
);
|
||||
};
|
@ -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;
|
||||
});
|
||||
};
|
@ -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);
|
||||
},
|
||||
);
|
||||
};
|
@ -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);
|
||||
});
|
||||
};
|
@ -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);
|
||||
});
|
||||
};
|
@ -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;
|
||||
},
|
||||
);
|
||||
};
|
@ -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);
|
||||
});
|
||||
};
|
@ -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());
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
@ -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);
|
||||
},
|
||||
);
|
||||
};
|
@ -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();
|
||||
});
|
||||
};
|
@ -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();
|
||||
});
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
import type { FastifyInstance } from "fastify";
|
||||
|
||||
export default (fastify: FastifyInstance) => {
|
||||
fastify.get("/", () => {
|
||||
return { appName: "code-containers" };
|
||||
});
|
||||
};
|
@ -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;
|
@ -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;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export interface Image {
|
||||
name: string;
|
||||
}
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user