From 33b81603cf65b04944dab5cade474df0d8e8b057 Mon Sep 17 00:00:00 2001 From: pankaj <0xpankaj@gmail.com> Date: Sat, 5 Apr 2025 04:38:08 +0545 Subject: [PATCH 1/3] adding differnt stack --- rust-backend/Cargo.toml | 6 ++++++ rust-backend/src/main.rs | 3 +++ 2 files changed, 9 insertions(+) create mode 100644 rust-backend/Cargo.toml create mode 100644 rust-backend/src/main.rs diff --git a/rust-backend/Cargo.toml b/rust-backend/Cargo.toml new file mode 100644 index 0000000..989c27b --- /dev/null +++ b/rust-backend/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust-backend" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/rust-backend/src/main.rs b/rust-backend/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/rust-backend/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 79c3ff7d2aea3b7afe35950fd43e7c9153dcd38c Mon Sep 17 00:00:00 2001 From: pankaj <0xpankaj@gmail.com> Date: Sat, 5 Apr 2025 04:46:02 +0545 Subject: [PATCH 2/3] working on dockerfile pod --- .../frontend/app/project/[projectId]/page.tsx | 26 +- .../frontend/components/ProjectsDrawer.tsx | 2 +- mobile-magic/apps/k8s-orchestrator/index.ts | 410 ++++++++++-------- mobile-magic/apps/k8s-orchestrator/redis.ts | 15 +- mobile-magic/apps/primary-backend/index.ts | 23 +- mobile-magic/bun.lock | 24 +- .../docker/Dockerfile.code-server-nextjs | 32 ++ .../docker/Dockerfile.code-server-react | 40 ++ .../docker/Dockerfile.code-server-react-expo | 32 ++ .../Dockerfile.code-server-rust-backend | 31 ++ mobile-magic/packages/common/.env.example | 1 + mobile-magic/packages/common/middleware.ts | 35 +- mobile-magic/packages/common/types.d.ts | 8 +- 13 files changed, 443 insertions(+), 236 deletions(-) create mode 100644 mobile-magic/docker/Dockerfile.code-server-nextjs create mode 100644 mobile-magic/docker/Dockerfile.code-server-react create mode 100644 mobile-magic/docker/Dockerfile.code-server-react-expo create mode 100644 mobile-magic/docker/Dockerfile.code-server-rust-backend create mode 100644 mobile-magic/packages/common/.env.example diff --git a/mobile-magic/apps/frontend/app/project/[projectId]/page.tsx b/mobile-magic/apps/frontend/app/project/[projectId]/page.tsx index 4f47bd0..4a4f190 100644 --- a/mobile-magic/apps/frontend/app/project/[projectId]/page.tsx +++ b/mobile-magic/apps/frontend/app/project/[projectId]/page.tsx @@ -3,18 +3,24 @@ import { K8S_ORCHESTRATOR_URL } from "@/config"; import ProjectWithInitRequest from "@/components/ProjectWithInitRequest"; interface Params { - params: Promise<{ projectId: string }> + params: Promise<{ projectId: string }>; } export default async function ProjectPage({ params }: Params) { - const projectId = (await params).projectId - const response = await axios.get(`${K8S_ORCHESTRATOR_URL}/worker/${projectId}`); - const { sessionUrl, previewUrl, workerUrl } = response.data; + const projectId = (await params).projectId; + console.log("k8s url: ", K8S_ORCHESTRATOR_URL); + console.log("projectId: ", projectId); + const response = await axios.get( + `${K8S_ORCHESTRATOR_URL}/worker/${projectId}`, + ); + const { sessionUrl, previewUrl, workerUrl } = response.data; - return + return ( + + ); } diff --git a/mobile-magic/apps/frontend/components/ProjectsDrawer.tsx b/mobile-magic/apps/frontend/components/ProjectsDrawer.tsx index 1a02abd..dc46c0b 100644 --- a/mobile-magic/apps/frontend/components/ProjectsDrawer.tsx +++ b/mobile-magic/apps/frontend/components/ProjectsDrawer.tsx @@ -8,7 +8,7 @@ import { DrawerTitle, } from "@/components/ui/drawer"; -import { SignedIn, useClerk, UserButton, useUser } from "@clerk/nextjs"; +import { SignedIn, UserButton, useUser } from "@clerk/nextjs"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { MessageSquareIcon, SearchIcon, UmbrellaOff } from "lucide-react"; diff --git a/mobile-magic/apps/k8s-orchestrator/index.ts b/mobile-magic/apps/k8s-orchestrator/index.ts index 5f43cc8..68dbd8d 100644 --- a/mobile-magic/apps/k8s-orchestrator/index.ts +++ b/mobile-magic/apps/k8s-orchestrator/index.ts @@ -1,29 +1,28 @@ -process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; -import express from 'express'; +process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; +import express from "express"; import { KubeConfig, CoreV1Api } from "@kubernetes/client-node"; import * as k8s from "@kubernetes/client-node"; -import cors from 'cors'; -import { Writable } from 'stream'; -import { DOMAIN } from './config'; -import { prismaClient } from "db/client"; -import promClient from 'prom-client'; +import cors from "cors"; +import { Writable } from "stream"; +import { DOMAIN } from "./config"; +import { prismaClient } from "db/client"; +import promClient from "prom-client"; const containerCreateBucket = new promClient.Histogram({ - name: 'container_create_bucket', - help: 'Number of times a container was created', - labelNames: ['type'], - buckets: [50, 100, 250, 500, 1000, 2500, 5000, 10000, 20000], + name: "container_create_bucket", + help: "Number of times a container was created", + labelNames: ["type"], + buckets: [50, 100, 250, 500, 1000, 2500, 5000, 10000, 20000], }); - const kc = new KubeConfig(); const app = express(); const PROJECT_TYPE_TO_BASE_FOLDER = { - NEXTJS: "/tmp/next-app", - REACT: "/tmp/react-app", - REACT_NATIVE: "/tmp/mobile-app" -} + NEXTJS: "/tmp/next-app", + REACT: "/tmp/react-app", + REACT_NATIVE: "/tmp/mobile-app", +}; kc.loadFromDefault(); @@ -34,188 +33,255 @@ const currentContext = kc.getCurrentContext(); const cluster = kc.getCluster(currentContext); async function listPods(): Promise { - const res = await k8sApi.listNamespacedPod({ namespace: 'user-apps' }); - console.log(res.items.map((pod) => pod.status?.phase)); - return res.items.filter(pod => pod.status?.phase === 'Running' || pod.status?.phase === 'Pending').filter(pod => pod.metadata?.name).map((pod) => pod.metadata?.name as string); + const res = await k8sApi.listNamespacedPod({ namespace: "user-apps" }); + console.log(res.items.map((pod) => pod.status?.phase)); + return res.items + .filter( + (pod) => + pod.status?.phase === "Running" || pod.status?.phase === "Pending", + ) + .filter((pod) => pod.metadata?.name) + .map((pod) => pod.metadata?.name as string); } -async function createPod(name: string) { - - await k8sApi.createNamespacedPod({ namespace: 'user-apps', body: { - metadata: { - name: name, - labels: { - app: name, - }, +async function createPod(name: string, projectType: ProjectType) { + await k8sApi.createNamespacedPod({ + namespace: "user-apps", + body: { + metadata: { + name: name, + labels: { + app: name, }, - spec: { - containers: [{ - name: "code-server", - image: '100xdevs/code-server-base:v3', - ports: [{ containerPort: 8080 }, { containerPort: 8081 }], - }, { - name: "ws-relayer", - image: "100xdevs/antidevs-ws-relayer:ff488d08f7a2bf15c77d9787352a79468c14fc3f", - ports: [{ containerPort: 9093 }], - }, { - name: "worker", - image: "100xdevs/antidevs-worker:ff488d08f7a2bf15c77d9787352a79468c14fc3f", - ports: [{ containerPort: 9091 }], - env: [{ - name: "WS_RELAYER_URL", - value: `ws://localhost:9091`, - }, { - name: "ANTHROPIC_API_KEY", - valueFrom: { - secretKeyRef: { - name: "worker-secret", - key: "ANTHROPIC_API_KEY", - } - } - }, { - name: "DATABASE_URL", - valueFrom: { - secretKeyRef: { - name: "worker-secret", - key: "DATABASE_URL", - } - } - }] - }], - }, - }}); + }, + spec: { + containers: [ + { + name: "code-server", + image: PROJECT_TYPE_TO_IMAGE[projectType], + ports: [{ containerPort: 8080 }, { containerPort: 8081 }], + }, + { + name: "ws-relayer", + image: + "100xdevs/antidevs-ws-relayer:ff488d08f7a2bf15c77d9787352a79468c14fc3f", + ports: [{ containerPort: 9093 }], + }, + { + name: "worker", + image: + "100xdevs/antidevs-worker:ff488d08f7a2bf15c77d9787352a79468c14fc3f", + ports: [{ containerPort: 9091 }], + env: [ + { + name: "WS_RELAYER_URL", + value: `ws://localhost:9091`, + }, + { + name: "ANTHROPIC_API_KEY", + valueFrom: { + secretKeyRef: { + name: "worker-secret", + key: "ANTHROPIC_API_KEY", + }, + }, + }, + { + name: "DATABASE_URL", + valueFrom: { + secretKeyRef: { + name: "worker-secret", + key: "DATABASE_URL", + }, + }, + }, + ], + }, + ], + }, + }, + }); - await k8sApi.createNamespacedService({ namespace: 'user-apps', body: { - metadata: { - name: `session-${name}`, - }, - spec: { - selector: { - app: name, - }, - ports: [{ port: 8080, targetPort: 8080, protocol: 'TCP', name: 'session' }], + await k8sApi.createNamespacedService({ + namespace: "user-apps", + body: { + metadata: { + name: `session-${name}`, + }, + spec: { + selector: { + app: name, }, - }}); + ports: [ + { port: 8080, targetPort: 8080, protocol: "TCP", name: "session" }, + ], + }, + }, + }); - await k8sApi.createNamespacedService({ namespace: 'user-apps', body: { - metadata: { - name: `preview-${name}`, - }, - spec: { - selector: { - app: name, - }, - ports: [{ port: 8080, targetPort: 8081, protocol: 'TCP', name: 'preview' }], + await k8sApi.createNamespacedService({ + namespace: "user-apps", + body: { + metadata: { + name: `preview-${name}`, + }, + spec: { + selector: { + app: name, }, - }}); + ports: [ + { port: 8080, targetPort: 8081, protocol: "TCP", name: "preview" }, + ], + }, + }, + }); - await k8sApi.createNamespacedService({ namespace: 'user-apps', body: { - metadata: { - name: `worker-${name}`, + await k8sApi.createNamespacedService({ + namespace: "user-apps", + body: { + metadata: { + name: `worker-${name}`, + }, + spec: { + selector: { + app: name, }, - spec: { - selector: { - app: name, - }, - ports: [{ port: 8080, targetPort: 9091, protocol: 'TCP', name: 'preview' }], - }, - }}); + ports: [ + { port: 8080, targetPort: 9091, protocol: "TCP", name: "preview" }, + ], + }, + }, + }); } async function checkPodIsReady(name: string) { - let attempts = 0; - while (true) { - const pod = await k8sApi.readNamespacedPod({ namespace: 'user-apps', name }); - if (pod.status?.phase === 'Running') { - return; - } - if (attempts > 10) { - throw new Error("Pod is not ready"); - } - //TODO: Exponential backoff - await new Promise((resolve) => setTimeout(resolve, 2000)); - attempts++; + let attempts = 0; + while (true) { + const pod = await k8sApi.readNamespacedPod({ + namespace: "user-apps", + name, + }); + if (pod.status?.phase === "Running") { + return; + } + if (attempts > 10) { + throw new Error("Pod is not ready"); } + //TODO: Exponential backoff + await new Promise((resolve) => setTimeout(resolve, 2000)); + attempts++; + } } -async function assignPodToProject(projectId: string, projectType: "NEXTJS" | "REACT_NATIVE" | "REACT") { - const pods = await listPods(); - const podExists = pods.find(pod => pod === projectId); - if (!podExists) { - console.log("Pod does not exist, creating pod"); - await createPod(projectId); - } +enum ProjectType { + REACT_NATIVE = "REACT_NATIVE", + NEXTJS = "NEXTJS", + REACT = "REACT", +} + +const PROJECT_TYPE_TO_IMAGE: Record = { + [ProjectType.NEXTJS]: "100xdevs/code-server-nextjs:v3", //100xdevs/code-server-base:v3 + [ProjectType.REACT]: "100xdevs/code-server-react:v3", + [ProjectType.REACT_NATIVE]: "100xdevs/code-server-react:v3", +}; - console.log("Pod exists, checking if it is ready"); - await checkPodIsReady(projectId); - console.log("Pod is ready, moving project to pod"); - - const exec = new k8s.Exec(kc); - let stdout = ""; - let stderr = ""; - console.log(`mv ${PROJECT_TYPE_TO_BASE_FOLDER[projectType]}/* /app`); - - exec.exec("user-apps", projectId, "code-server", ["/bin/sh", "-c", `mv ${PROJECT_TYPE_TO_BASE_FOLDER[projectType]}/* /app`], - new Writable({ - write: (chunk: Buffer, encoding: BufferEncoding, callback: () => void) => { - stdout += chunk; - callback(); - } - }), - new Writable({ - write: (chunk: Buffer, encoding: BufferEncoding, callback: () => void) => { - stderr += chunk; - callback(); - } - }), - null, - false, - (status) => { - console.log(status); - console.log(stdout); - console.log(stderr); - } - ); - - await new Promise((resolve) => setTimeout(resolve, 1000)); - console.log(stdout); - console.log(stderr); - - console.log(`Assigned project ${projectId} to pod ${projectId}`); +async function assignPodToProject(projectId: string, projectType: ProjectType) { + const pods = await listPods(); + const podExists = pods.find((pod) => pod === projectId); + if (!podExists) { + console.log("Pod does not exist, creating pod"); + + await createPod(projectId, projectType); + } + + console.log("Pod exists, checking if it is ready"); + await checkPodIsReady(projectId); + console.log("Pod is ready, moving project to pod"); + + const exec = new k8s.Exec(kc); + let stdout = ""; + let stderr = ""; + console.log(`mv ${PROJECT_TYPE_TO_BASE_FOLDER[projectType]}/* /app`); + + exec.exec( + "user-apps", + projectId, + "code-server", + ["/bin/sh", "-c", `mv ${PROJECT_TYPE_TO_BASE_FOLDER[projectType]}/* /app`], + new Writable({ + write: ( + chunk: Buffer, + encoding: BufferEncoding, + callback: () => void, + ) => { + stdout += chunk; + callback(); + }, + }), + new Writable({ + write: ( + chunk: Buffer, + encoding: BufferEncoding, + callback: () => void, + ) => { + stderr += chunk; + callback(); + }, + }), + null, + false, + (status) => { + console.log(status); + console.log(stdout); + console.log(stderr); + }, + ); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + console.log(stdout); + console.log(stderr); + + console.log(`Assigned project ${projectId} to pod ${projectId}`); } app.get("/worker/:projectId", async (req, res) => { - console.log("Received request to assign project to pod for project", req.params.projectId); - const { projectId } = req.params; - const project = await prismaClient.project.findUnique({ - where: { - id: projectId, - }, - }); + console.log( + "Received request to assign project to pod for project", + req.params.projectId, + ); + const { projectId } = req.params; + const project = await prismaClient.project.findUnique({ + where: { + id: projectId, + }, + }); - if (!project) { - res.status(404).json({ error: "Project not found" }); - return; - } + const projectType = project?.type; - console.log("Project found, assigning to pod"); - const startTime = Date.now(); - await assignPodToProject(projectId, "REACT"); - console.log("Pod assigned, sending response"); - containerCreateBucket.observe({ type: project.type }, Date.now() - startTime); + if (!project) { + res.status(404).json({ error: "Project not found" }); + return; + } - res.json({ - sessionUrl: `https://session-${projectId}.${DOMAIN}`, - previewUrl: `https://preview-${projectId}.${DOMAIN}`, - workerUrl: `https://worker-${projectId}.${DOMAIN}` - }); + console.log("Project found, assigning to pod"); + const startTime = Date.now(); + //assigning project accourding to type user requested + await assignPodToProject(projectId, projectType! as ProjectType); + console.log("Pod assigned, sending response"); + containerCreateBucket.observe({ type: project.type }, Date.now() - startTime); + + res.json({ + sessionUrl: `https://session-${projectId}.${DOMAIN}`, + previewUrl: `https://preview-${projectId}.${DOMAIN}`, + workerUrl: `https://worker-${projectId}.${DOMAIN}`, + }); }); app.get("/metrics", async (req, res) => { - res.setHeader('Content-Type', promClient.register.contentType); - res.end(await promClient.register.metrics()); + res.setHeader("Content-Type", promClient.register.contentType); + res.end(await promClient.register.metrics()); }); app.listen(7001, () => { - console.log("Server is running on port 7001"); + console.log("Server is running on port 7001"); }); diff --git a/mobile-magic/apps/k8s-orchestrator/redis.ts b/mobile-magic/apps/k8s-orchestrator/redis.ts index f04173d..66be1fa 100644 --- a/mobile-magic/apps/k8s-orchestrator/redis.ts +++ b/mobile-magic/apps/k8s-orchestrator/redis.ts @@ -6,21 +6,20 @@ export const redisClient = createClient({ redisClient.connect(); export async function addNewPod(pod: string) { - // add expiry of 5 minutes - await redisClient.hSet("POD_MAPPING", pod, "empty"); - await redisClient.expire("POD_MAPPING", 300); // expire after 5 minutes + // add expiry of 5 minutes + await redisClient.hSet("POD_MAPPING", pod, "empty"); + await redisClient.expire("POD_MAPPING", 300); // expire after 5 minutes } export async function removePod(pod: string) { - await redisClient.hDel("POD_MAPPING", pod); + await redisClient.hDel("POD_MAPPING", pod); } export function getAllPods() { - return redisClient.hGetAll("POD_MAPPING"); + return redisClient.hGetAll("POD_MAPPING"); } export async function addProjectToPod(projectId: string, pod: string) { - await redisClient.hSet("POD_MAPPING", pod, projectId); - await redisClient.expire("POD_MAPPING", 300); // expire after 5 minutes + await redisClient.hSet("POD_MAPPING", pod, projectId); + await redisClient.expire("POD_MAPPING", 300); // expire after 5 minutes } - diff --git a/mobile-magic/apps/primary-backend/index.ts b/mobile-magic/apps/primary-backend/index.ts index d33ba1b..d0f5b05 100644 --- a/mobile-magic/apps/primary-backend/index.ts +++ b/mobile-magic/apps/primary-backend/index.ts @@ -2,18 +2,19 @@ import { prismaClient } from "db/client"; import express from "express"; import cors from "cors"; import { authMiddleware } from "common/middleware"; -import promMid from 'express-prometheus-middleware' +import promMid from "express-prometheus-middleware"; const app = express(); -app.use(promMid({ - metricsPath: '/metrics', - collectDefaultMetrics: true, - requestDurationBuckets: [0.1, 0.5, 1, 1.5], - requestLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400], - responseLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400], -})); - +app.use( + promMid({ + metricsPath: "/metrics", + collectDefaultMetrics: true, + requestDurationBuckets: [0.1, 0.5, 1, 1.5], + requestLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400], + responseLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400], + }), +); app.use(express.json()); app.use(cors()); @@ -31,9 +32,11 @@ app.post("/project", authMiddleware, async (req, res) => { app.get("/projects", authMiddleware, async (req, res) => { const userId = req.userId!; + console.log("userId: ", userId); const projects = await prismaClient.project.findMany({ where: { userId }, }); + console.log("projects: ", projects); res.json({ projects }); }); @@ -52,4 +55,4 @@ app.get("/prompts/:projectId", authMiddleware, async (req, res) => { app.listen(9090, () => { console.log("Server is running on port 9090"); -}); \ No newline at end of file +}); diff --git a/mobile-magic/bun.lock b/mobile-magic/bun.lock index c3cfc78..6ced5f3 100644 --- a/mobile-magic/bun.lock +++ b/mobile-magic/bun.lock @@ -2122,7 +2122,7 @@ "jsonwebtoken/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], - "k8s-orchestrator/@types/bun": ["@types/bun@1.2.5", "", { "dependencies": { "bun-types": "1.2.5" } }, "sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg=="], + "k8s-orchestrator/@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="], "log-symbols/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], @@ -2146,7 +2146,7 @@ "postcss/picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "primary-backend/@types/bun": ["@types/bun@1.2.5", "", { "dependencies": { "bun-types": "1.2.5" } }, "sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg=="], + "primary-backend/@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="], "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], @@ -2182,9 +2182,9 @@ "use-sidecar/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "worker/@types/bun": ["@types/bun@1.2.5", "", { "dependencies": { "bun-types": "1.2.5" } }, "sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg=="], + "worker/@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="], - "ws-relayer/@types/bun": ["@types/bun@1.2.5", "", { "dependencies": { "bun-types": "1.2.5" } }, "sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg=="], + "ws-relayer/@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="], "@anthropic-ai/sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], @@ -2216,7 +2216,7 @@ "inquirer/ora/log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], - "k8s-orchestrator/@types/bun/bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="], + "k8s-orchestrator/@types/bun/bun-types": ["bun-types@1.2.7", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-P4hHhk7kjF99acXqKvltyuMQ2kf/rzIw3ylEDpCxDS9Xa0X0Yp/gJu/vDCucmWpiur5qJ0lwB2bWzOXa2GlHqA=="], "log-symbols/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], @@ -2230,7 +2230,7 @@ "node-plop/inquirer/rxjs": ["rxjs@6.6.7", "", { "dependencies": { "tslib": "^1.9.0" } }, "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ=="], - "primary-backend/@types/bun/bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="], + "primary-backend/@types/bun/bun-types": ["bun-types@1.2.7", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-P4hHhk7kjF99acXqKvltyuMQ2kf/rzIw3ylEDpCxDS9Xa0X0Yp/gJu/vDCucmWpiur5qJ0lwB2bWzOXa2GlHqA=="], "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -2238,16 +2238,14 @@ "snakecase-keys/snake-case/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "worker/@types/bun/bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="], + "worker/@types/bun/bun-types": ["bun-types@1.2.7", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-P4hHhk7kjF99acXqKvltyuMQ2kf/rzIw3ylEDpCxDS9Xa0X0Yp/gJu/vDCucmWpiur5qJ0lwB2bWzOXa2GlHqA=="], - "ws-relayer/@types/bun/bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="], + "ws-relayer/@types/bun/bun-types": ["bun-types@1.2.7", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-P4hHhk7kjF99acXqKvltyuMQ2kf/rzIw3ylEDpCxDS9Xa0X0Yp/gJu/vDCucmWpiur5qJ0lwB2bWzOXa2GlHqA=="], "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - "k8s-orchestrator/@types/bun/bun-types/@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], - "log-symbols/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], "log-symbols/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], @@ -2256,14 +2254,8 @@ "node-plop/inquirer/rxjs/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], - "primary-backend/@types/bun/bun-types/@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], - "snakecase-keys/snake-case/dot-case/no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="], - "worker/@types/bun/bun-types/@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], - - "ws-relayer/@types/bun/bun-types/@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], - "log-symbols/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], "minizlib/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], diff --git a/mobile-magic/docker/Dockerfile.code-server-nextjs b/mobile-magic/docker/Dockerfile.code-server-nextjs new file mode 100644 index 0000000..bcf2cc4 --- /dev/null +++ b/mobile-magic/docker/Dockerfile.code-server-nextjs @@ -0,0 +1,32 @@ +FROM codercom/code-server:4.96.4 + +USER root +RUN apt-get update \ + && apt-get install -y curl \ + && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +USER coder +EXPOSE 8080 + +# Clone repo and copy Next.js template +RUN git clone https://github.com/code100x/mobile-magic.git /tmp/bolty-worker \ + && cp -r /tmp/bolty-worker/nextjs-base-app /app \ + && rm -rf /tmp/bolty-worker + + +WORKDIR /app +# RUN npm install //still update on dependency will rebuild so no benefit of pre-build just larger image size + + +RUN wget https://github.com/code100x/mobile-magic/raw/refs/heads/main/ext/bolty-listener-0.0.1.vsix \ + && code-server --install-extension bolty-listener-0.0.1.vsix \ + && rm bolty-listener-0.0.1.vsix + + +RUN mkdir -p /home/coder/.local/share/code-server/User \ + && echo '{"workbench.colorTheme": "Dark+", "workbench.preferredDarkColorTheme": "Dark+"}' > /home/coder/.local/share/code-server/User/settings.json + +CMD ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080", "--disable-telemetry", "/app"] diff --git a/mobile-magic/docker/Dockerfile.code-server-react b/mobile-magic/docker/Dockerfile.code-server-react new file mode 100644 index 0000000..eb4423f --- /dev/null +++ b/mobile-magic/docker/Dockerfile.code-server-react @@ -0,0 +1,40 @@ +FROM codercom/code-server:4.96.4 + +USER root +RUN apt-get update \ + && apt-get install -y curl \ + && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Revert to the code-server default user +USER coder +# Expose code-server's default port +EXPOSE 8080 + +RUN git clone https://github.com/code100x/mobile-magic.git /tmp/bolty-worker +RUN cp -r /tmp/bolty-worker/react-base-app /tmp/react-app + + +RUN cd /tmp +WORKDIR /app +# RUN npm install //still update on dependency will rebuild so no benefit of pre-build just larger image size + +WORKDIR /tmp + +RUN wget https://github.com/code100x/mobile-magic/raw/refs/heads/main/ext/bolty-listener-0.0.1.vsix +RUN code-server --install-extension bolty-listener-0.0.1.vsix + +RUN sudo chown -R coder /tmp/bolty-worker +RUN sudo chown -R coder /tmp/react-app +RUN sudo chown -R coder /app + +RUN rm -rf /tmp/bolty-worker + +# Set default theme to dark +RUN mkdir -p /home/coder/.local/share/code-server/User +RUN echo '{"workbench.colorTheme": "Dark+", "workbench.preferredDarkColorTheme": "Dark+"}' > /home/coder/.local/share/code-server/User/settings.json + +# Start code-server on container launch +CMD ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080", "--disable-telemetry", "/app"] diff --git a/mobile-magic/docker/Dockerfile.code-server-react-expo b/mobile-magic/docker/Dockerfile.code-server-react-expo new file mode 100644 index 0000000..9ff9f78 --- /dev/null +++ b/mobile-magic/docker/Dockerfile.code-server-react-expo @@ -0,0 +1,32 @@ +FROM codercom/code-server:4.96.4 + +USER root +RUN apt-get update \ + && apt-get install -y curl \ + && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +USER coder +EXPOSE 8080 + +# Clone repo and copy React Native template +RUN git clone https://github.com/code100x/mobile-magic.git /tmp/bolty-worker \ + && cp -r /tmp/bolty-worker/expo-base-app /app \ + && rm -rf /tmp/bolty-worker + + +WORKDIR /app +# RUN npm install //still update on dependency will rebuild so no benefit of pre-build just larger image size + + +RUN wget https://github.com/code100x/mobile-magic/raw/refs/heads/main/ext/bolty-listener-0.0.1.vsix \ + && code-server --install-extension bolty-listener-0.0.1.vsix \ + && rm bolty-listener-0.0.1.vsix + + +RUN mkdir -p /home/coder/.local/share/code-server/User \ + && echo '{"workbench.colorTheme": "Dark+", "workbench.preferredDarkColorTheme": "Dark+"}' > /home/coder/.local/share/code-server/User/settings.json + +CMD ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080", "--disable-telemetry", "/app"] diff --git a/mobile-magic/docker/Dockerfile.code-server-rust-backend b/mobile-magic/docker/Dockerfile.code-server-rust-backend new file mode 100644 index 0000000..0cf8a0e --- /dev/null +++ b/mobile-magic/docker/Dockerfile.code-server-rust-backend @@ -0,0 +1,31 @@ +FROM codercom/code-server:4.96.4 + +USER root +RUN apt-get update \ + && apt-get install -y curl \ + && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +USER coder +EXPOSE 8080 + +# Clone repo and copy Rust template (adjust path when available) +RUN git clone https://github.com/code100x/mobile-magic.git /tmp/bolty-worker \ + && cp -r /tmp/bolty-worker/rust-backend /app \ + && rm -rf /tmp/bolty-worker + + +WORKDIR /app + //working on it + + +RUN wget https://github.com/code100x/mobile-magic/raw/refs/heads/main/ext/bolty-listener-0.0.1.vsix \ + && code-server --install-extension bolty-listener-0.0.1.vsix \ + && rm bolty-listener-0.0.1.vsix + + +RUN mkdir -p /home/coder/.local/share/code-server/User \ + && echo '{"workbench.colorTheme": "Dark+", "workbench.preferredDarkColorTheme": "Dark+"}' > /home/coder/.local/share/code-server/User/settings.json + +CMD ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080", "--disable-telemetry", "/app"] diff --git a/mobile-magic/packages/common/.env.example b/mobile-magic/packages/common/.env.example new file mode 100644 index 0000000..b2c5dcf --- /dev/null +++ b/mobile-magic/packages/common/.env.example @@ -0,0 +1 @@ +JWT_PUBLIC_KEY= diff --git a/mobile-magic/packages/common/middleware.ts b/mobile-magic/packages/common/middleware.ts index 09bd431..2818985 100644 --- a/mobile-magic/packages/common/middleware.ts +++ b/mobile-magic/packages/common/middleware.ts @@ -1,34 +1,41 @@ import type { NextFunction, Request, Response } from "express"; import jwt from "jsonwebtoken"; -const JWT_PUBLIC_KEY = process.env.JWT_PUBLIC_KEY ?? `-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7JkM9KqFNyC0B0ILTKJL -vOgqXrfDqhW9rwpq5Pn2Vyhp0DdzmSGPzY+H/2EMzZzc//9b8eX6fxZIrW02uQ7o -o1P6dv40vZab2Ie6tgpeKvSLyFcpdbZLWaDX4wH22uVnw7YH/yKdt3vEoSO+Pgev -wIcSyh1w92x1TZ/obSTUpSJ0Ll5A4bR+WUsMqw2pxmKJR6onEoMSUAztGTTqrcdk -32rnk/D3uFe2li5TtsL0Ytsj7CwyfpbHzpfDrqcdOHPEXptH4ALB14WvlHm0wrgw -Aru84NfJ1dH3q/AbNdUGHbLaHJfagSwLMfF5UyxZw8+SgBa5XDUTQu3JXE9GA65Y -DwIDAQAB ------END PUBLIC KEY-----`; - -export function authMiddleware(req: Request, res: Response, next: NextFunction) { +declare global { + namespace Express { + interface Request { + userId?: string; + } + } +} + +const JWT_PUBLIC_KEY = process.env.JWT_PUBLIC_KEY; + +console.log("jwtkey: ", JWT_PUBLIC_KEY); + +export function authMiddleware( + req: Request, + res: Response, + next: NextFunction, +) { const authHeader = req.headers.authorization; // Bearer token const token = authHeader && authHeader.split(" ")[1]; + console.log("token: ", token); if (!token) { res.status(401).json({ message: "Unauthorized" }); return; } - const decoded = jwt.verify(token, JWT_PUBLIC_KEY!, { - algorithms: ["RS256"], - }); + const decoded = jwt.verify(token, JWT_PUBLIC_KEY!); if (!decoded) { res.status(401).json({ message: "Unauthorized" }); return; } + console.log("decoded: ", decoded); + const userId = (decoded as any).sub; if (!userId) { diff --git a/mobile-magic/packages/common/types.d.ts b/mobile-magic/packages/common/types.d.ts index a00caca..c10892f 100644 --- a/mobile-magic/packages/common/types.d.ts +++ b/mobile-magic/packages/common/types.d.ts @@ -1,7 +1,5 @@ - declare namespace Express { - interface Request { - userId?: string; - } + interface Request { + userId?: string; } - \ No newline at end of file +} From e411c2ddcc939695f08341bd439c083c4f3ba82e Mon Sep 17 00:00:00 2001 From: pankaj <0xpankaj@gmail.com> Date: Sun, 6 Apr 2025 19:55:21 +0545 Subject: [PATCH 3/3] added s3 and many thing --- .../frontend/app/project/[projectId]/page.tsx | 1 + mobile-magic/apps/k8s-orchestrator/config.ts | 4 +- mobile-magic/apps/k8s-orchestrator/index.ts | 201 +++++++++++++----- .../apps/k8s-orchestrator/package.json | 1 + mobile-magic/bun.lock | 49 ++++- ...eact => Dockerfile.code-server-base-image} | 21 +- .../docker/Dockerfile.code-server-nextjs | 32 --- .../docker/Dockerfile.code-server-node | 52 +++++ .../docker/Dockerfile.code-server-react-expo | 32 --- mobile-magic/packages/db/index.ts | 1 - mobile-magic/packages/db/prisma/schema.prisma | 19 +- 11 files changed, 260 insertions(+), 153 deletions(-) rename mobile-magic/docker/{Dockerfile.code-server-react => Dockerfile.code-server-base-image} (56%) delete mode 100644 mobile-magic/docker/Dockerfile.code-server-nextjs create mode 100644 mobile-magic/docker/Dockerfile.code-server-node delete mode 100644 mobile-magic/docker/Dockerfile.code-server-react-expo diff --git a/mobile-magic/apps/frontend/app/project/[projectId]/page.tsx b/mobile-magic/apps/frontend/app/project/[projectId]/page.tsx index 4a4f190..72f289c 100644 --- a/mobile-magic/apps/frontend/app/project/[projectId]/page.tsx +++ b/mobile-magic/apps/frontend/app/project/[projectId]/page.tsx @@ -13,6 +13,7 @@ export default async function ProjectPage({ params }: Params) { const response = await axios.get( `${K8S_ORCHESTRATOR_URL}/worker/${projectId}`, ); + console.log("response from orchestrator worker : ", response); const { sessionUrl, previewUrl, workerUrl } = response.data; return ( diff --git a/mobile-magic/apps/k8s-orchestrator/config.ts b/mobile-magic/apps/k8s-orchestrator/config.ts index 42f954a..77e0d90 100644 --- a/mobile-magic/apps/k8s-orchestrator/config.ts +++ b/mobile-magic/apps/k8s-orchestrator/config.ts @@ -1,2 +1,2 @@ - -export const DOMAIN = "cloud.antidevs.com"; \ No newline at end of file +// export const DOMAIN = "cloud.antidevs.com"; +export const DOMAIN = "localhost"; diff --git a/mobile-magic/apps/k8s-orchestrator/index.ts b/mobile-magic/apps/k8s-orchestrator/index.ts index 68dbd8d..174d2a7 100644 --- a/mobile-magic/apps/k8s-orchestrator/index.ts +++ b/mobile-magic/apps/k8s-orchestrator/index.ts @@ -7,6 +7,7 @@ import { Writable } from "stream"; import { DOMAIN } from "./config"; import { prismaClient } from "db/client"; import promClient from "prom-client"; +import AWS from "aws-sdk"; const containerCreateBucket = new promClient.Histogram({ name: "container_create_bucket", @@ -18,6 +19,10 @@ const containerCreateBucket = new promClient.Histogram({ const kc = new KubeConfig(); const app = express(); +const s3 = new AWS.S3({ + region: "", +}); + const PROJECT_TYPE_TO_BASE_FOLDER = { NEXTJS: "/tmp/next-app", REACT: "/tmp/react-app", @@ -44,7 +49,38 @@ async function listPods(): Promise { .map((pod) => pod.metadata?.name as string); } -async function createPod(name: string, projectType: ProjectType) { +enum ProjectType { + REACT_NATIVE = "REACT_NATIVE", + REACT = "REACT", + NEXTJS = "NEXTJS", +} + +const PROJECT_TYPE_TO_BASE_IMAGE: Record = { + [ProjectType.NEXTJS]: "100xdevs/code-server-nextjs:v3", //100xdevs/code-server-base:v3 + [ProjectType.REACT]: "100xdevs/code-server-react:v3", + [ProjectType.REACT_NATIVE]: "100xdevs/code-server-reactnative-expo:v3", +}; + +const RUNTIME_TO_BASE_IMAGE: Record = { + nodejs: "100xdevs/code-server-nodejs:v1", // Base image with Node.js only + rust: "100xdevs/code-server-rust:v1", // Base image with Rust only + nodejs_rust: "100xdevs/code-server-nodejs-rust:v1", // Base image with Node.js and Rust +}; + +//determing runtime based on project type +function getRuntimeForProjectType(projectType: ProjectType): string { + switch (projectType) { + case ProjectType.NEXTJS: + case ProjectType.REACT: + return "nodejs"; + case ProjectType.REACT_NATIVE: + return "nodejs"; + default: + return "nodejs"; // Default to Node.js + } +} + +async function createPod(name: string, image: string) { await k8sApi.createNamespacedPod({ namespace: "user-apps", body: { @@ -58,7 +94,7 @@ async function createPod(name: string, projectType: ProjectType) { containers: [ { name: "code-server", - image: PROJECT_TYPE_TO_IMAGE[projectType], + image: image, //here adding dynamic image //100xdevs/code-server-base:v3 ports: [{ containerPort: 8080 }, { containerPort: 8081 }], }, { @@ -173,25 +209,22 @@ async function checkPodIsReady(name: string) { } } -enum ProjectType { - REACT_NATIVE = "REACT_NATIVE", - NEXTJS = "NEXTJS", - REACT = "REACT", -} - -const PROJECT_TYPE_TO_IMAGE: Record = { - [ProjectType.NEXTJS]: "100xdevs/code-server-nextjs:v3", //100xdevs/code-server-base:v3 - [ProjectType.REACT]: "100xdevs/code-server-react:v3", - [ProjectType.REACT_NATIVE]: "100xdevs/code-server-react:v3", -}; - -async function assignPodToProject(projectId: string, projectType: ProjectType) { +async function assignPodToProject( + projectId: string, + projectType: ProjectType, + isOnS3: boolean, +) { const pods = await listPods(); const podExists = pods.find((pod) => pod === projectId); + + //determing base image + const image = isOnS3 + ? RUNTIME_TO_BASE_IMAGE[getRuntimeForProjectType(projectType)] + : PROJECT_TYPE_TO_BASE_IMAGE[projectType]; + if (!podExists) { console.log("Pod does not exist, creating pod"); - - await createPod(projectId, projectType); + await createPod(projectId, image); } console.log("Pod exists, checking if it is ready"); @@ -201,41 +234,95 @@ async function assignPodToProject(projectId: string, projectType: ProjectType) { const exec = new k8s.Exec(kc); let stdout = ""; let stderr = ""; - console.log(`mv ${PROJECT_TYPE_TO_BASE_FOLDER[projectType]}/* /app`); - - exec.exec( - "user-apps", - projectId, - "code-server", - ["/bin/sh", "-c", `mv ${PROJECT_TYPE_TO_BASE_FOLDER[projectType]}/* /app`], - new Writable({ - write: ( - chunk: Buffer, - encoding: BufferEncoding, - callback: () => void, - ) => { - stdout += chunk; - callback(); - }, - }), - new Writable({ - write: ( - chunk: Buffer, - encoding: BufferEncoding, - callback: () => void, - ) => { - stderr += chunk; - callback(); + + if (isOnS3) { + //pulling code from S3 + const s3Bucket = ""; + const s3Key = ""; + + const command = [ + "/bin/sh", + "-c", + `aws s3 cp s3://${s3Bucket}/${s3Key} /tmp/code.zip && unzip /tmp/code.zip -d /app && rm /tmp/code.zip`, + ]; + await new Promise((resolve, reject) => { + exec.exec( + "user-apps", + projectId, + "code-server", + command, + new Writable({ + write: ( + chunk: Buffer, + encoding: BufferEncoding, + callback: () => void, + ) => { + stdout += chunk; + callback(); + }, + }), + new Writable({ + write: ( + chunk: Buffer, + encoding: BufferEncoding, + callback: () => void, + ) => { + stderr += chunk; + callback(); + }, + }), + null, + false, + (status) => { + console.log("Exec status:", status); + console.log("Stdout:", stdout); + console.log("Stderr:", stderr); + if (status?.status === "Success") resolve(status); + else reject(new Error("Failed to pull and extract S3 code")); + }, + ); + }); + } else { + console.log(`mv ${PROJECT_TYPE_TO_BASE_FOLDER[projectType]}/* /app`); + + exec.exec( + "user-apps", + projectId, + "code-server", + [ + "/bin/sh", + "-c", + `mv ${PROJECT_TYPE_TO_BASE_FOLDER[projectType]}/* /app`, + ], + new Writable({ + write: ( + chunk: Buffer, + encoding: BufferEncoding, + callback: () => void, + ) => { + stdout += chunk; + callback(); + }, + }), + new Writable({ + write: ( + chunk: Buffer, + encoding: BufferEncoding, + callback: () => void, + ) => { + stderr += chunk; + callback(); + }, + }), + null, + false, + (status) => { + console.log(status); + console.log(stdout); + console.log(stderr); }, - }), - null, - false, - (status) => { - console.log(status); - console.log(stdout); - console.log(stderr); - }, - ); + ); + } await new Promise((resolve) => setTimeout(resolve, 1000)); console.log(stdout); @@ -256,17 +343,21 @@ app.get("/worker/:projectId", async (req, res) => { }, }); - const projectType = project?.type; - if (!project) { res.status(404).json({ error: "Project not found" }); return; } + const projectType = project.type as ProjectType; + const isOnS3 = project.onS3; + //if code is on s3 then we don't needed baseimage with initial code + // only needed baseimage with respective run time + console.log("Project found, assigning to pod"); const startTime = Date.now(); - //assigning project accourding to type user requested - await assignPodToProject(projectId, projectType! as ProjectType); + + await assignPodToProject(projectId, projectType, isOnS3); //argument as projectType + console.log("Pod assigned, sending response"); containerCreateBucket.observe({ type: project.type }, Date.now() - startTime); diff --git a/mobile-magic/apps/k8s-orchestrator/package.json b/mobile-magic/apps/k8s-orchestrator/package.json index 317015c..e0ca639 100644 --- a/mobile-magic/apps/k8s-orchestrator/package.json +++ b/mobile-magic/apps/k8s-orchestrator/package.json @@ -12,6 +12,7 @@ "@kubernetes/client-node": "^1.0.0", "@types/cors": "^2.8.17", "@types/express": "^5.0.0", + "aws-sdk": "^2.1692.0", "cors": "^2.8.5", "db": "*", "express": "^4.21.2", diff --git a/mobile-magic/bun.lock b/mobile-magic/bun.lock index 6ced5f3..d13e6ab 100644 --- a/mobile-magic/bun.lock +++ b/mobile-magic/bun.lock @@ -56,6 +56,7 @@ "@kubernetes/client-node": "^1.0.0", "@types/cors": "^2.8.17", "@types/express": "^5.0.0", + "aws-sdk": "^2.1692.0", "cors": "^2.8.5", "db": "*", "express": "^4.21.2", @@ -810,6 +811,8 @@ "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + "aws-sdk": ["aws-sdk@2.1692.0", "", { "dependencies": { "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", "util": "^0.12.4", "uuid": "8.0.0", "xml2js": "0.6.2" } }, "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw=="], + "axe-core": ["axe-core@4.10.3", "", {}, "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg=="], "axios": ["axios@1.8.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg=="], @@ -834,7 +837,7 @@ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + "buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="], "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], @@ -1054,6 +1057,8 @@ "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + "events": ["events@1.1.1", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="], + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], @@ -1190,7 +1195,7 @@ "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "ieee754": ["ieee754@1.1.13", "", {}, "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -1214,6 +1219,8 @@ "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + "is-arguments": ["is-arguments@1.2.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA=="], + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], @@ -1282,7 +1289,7 @@ "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], - "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], "isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="], @@ -1296,6 +1303,8 @@ "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], + "jmespath": ["jmespath@0.16.0", "", {}, "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw=="], + "jose": ["jose@6.0.8", "", {}, "sha512-EyUPtOKyTYq+iMOszO42eobQllaIjJnwkZ2U93aJzNyPibCy7CEvT9UQnaCVB51IAd49gbNdCew1c0LcLTCB2g=="], "js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="], @@ -1570,10 +1579,12 @@ "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + "punycode": ["punycode@1.3.2", "", {}, "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="], "qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], + "querystring": ["querystring@0.2.0", "", {}, "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], @@ -1640,6 +1651,8 @@ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "sax": ["sax@1.2.1", "", {}, "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="], + "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="], "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -1838,6 +1851,8 @@ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "url": ["url@0.10.3", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ=="], + "url-value-parser": ["url-value-parser@2.2.0", "", {}, "sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A=="], "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], @@ -1846,11 +1861,13 @@ "use-sync-external-store": ["use-sync-external-store@1.4.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw=="], + "util": ["util@0.12.5", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], - "uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + "uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="], "v8-compile-cache-lib": ["v8-compile-cache-lib@3.0.1", "", {}, "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="], @@ -1896,6 +1913,10 @@ "ws-relayer": ["ws-relayer@workspace:apps/ws-relayer"], + "xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="], + + "xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], "yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="], @@ -1920,6 +1941,8 @@ "@aws-sdk/client-ec2/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@aws-sdk/client-ec2/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + "@aws-sdk/client-sso/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "@aws-sdk/core/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -2010,6 +2033,8 @@ "@smithy/middleware-retry/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + "@smithy/middleware-serde/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "@smithy/middleware-stack/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -2084,8 +2109,12 @@ "ast-types/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "bun-types/@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], "eslint-config-next/@next/eslint-plugin-next": ["@next/eslint-plugin-next@15.2.1-canary.1", "", { "dependencies": { "fast-glob": "3.3.1" } }, "sha512-MByTwWAK/O5IvYvgkWupgOZ15d5VzLkUFOJ9TG70qUrOaQL9hcbBhiQGs/IKTaJKm5nb7sKdayCjibWNbHLJfw=="], @@ -2158,6 +2187,10 @@ "rxjs/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "safe-array-concat/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "safe-push-apply/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], @@ -2178,10 +2211,14 @@ "tinyglobby/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + "use-callback-ref/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "use-sidecar/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "worker/@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="], "ws-relayer/@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="], @@ -2204,6 +2241,8 @@ "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + "bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], diff --git a/mobile-magic/docker/Dockerfile.code-server-react b/mobile-magic/docker/Dockerfile.code-server-base-image similarity index 56% rename from mobile-magic/docker/Dockerfile.code-server-react rename to mobile-magic/docker/Dockerfile.code-server-base-image index eb4423f..6cd2ff4 100644 --- a/mobile-magic/docker/Dockerfile.code-server-react +++ b/mobile-magic/docker/Dockerfile.code-server-base-image @@ -1,5 +1,8 @@ FROM codercom/code-server:4.96.4 +# build arg for projectType +ARG projectType + USER root RUN apt-get update \ && apt-get install -y curl \ @@ -13,28 +16,14 @@ USER coder # Expose code-server's default port EXPOSE 8080 -RUN git clone https://github.com/code100x/mobile-magic.git /tmp/bolty-worker -RUN cp -r /tmp/bolty-worker/react-base-app /tmp/react-app - - -RUN cd /tmp -WORKDIR /app -# RUN npm install //still update on dependency will rebuild so no benefit of pre-build just larger image size - -WORKDIR /tmp - -RUN wget https://github.com/code100x/mobile-magic/raw/refs/heads/main/ext/bolty-listener-0.0.1.vsix -RUN code-server --install-extension bolty-listener-0.0.1.vsix -RUN sudo chown -R coder /tmp/bolty-worker -RUN sudo chown -R coder /tmp/react-app -RUN sudo chown -R coder /app -RUN rm -rf /tmp/bolty-worker # Set default theme to dark RUN mkdir -p /home/coder/.local/share/code-server/User RUN echo '{"workbench.colorTheme": "Dark+", "workbench.preferredDarkColorTheme": "Dark+"}' > /home/coder/.local/share/code-server/User/settings.json +WORKDIR /app + # Start code-server on container launch CMD ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080", "--disable-telemetry", "/app"] diff --git a/mobile-magic/docker/Dockerfile.code-server-nextjs b/mobile-magic/docker/Dockerfile.code-server-nextjs deleted file mode 100644 index bcf2cc4..0000000 --- a/mobile-magic/docker/Dockerfile.code-server-nextjs +++ /dev/null @@ -1,32 +0,0 @@ -FROM codercom/code-server:4.96.4 - -USER root -RUN apt-get update \ - && apt-get install -y curl \ - && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ - && apt-get install -y nodejs \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -USER coder -EXPOSE 8080 - -# Clone repo and copy Next.js template -RUN git clone https://github.com/code100x/mobile-magic.git /tmp/bolty-worker \ - && cp -r /tmp/bolty-worker/nextjs-base-app /app \ - && rm -rf /tmp/bolty-worker - - -WORKDIR /app -# RUN npm install //still update on dependency will rebuild so no benefit of pre-build just larger image size - - -RUN wget https://github.com/code100x/mobile-magic/raw/refs/heads/main/ext/bolty-listener-0.0.1.vsix \ - && code-server --install-extension bolty-listener-0.0.1.vsix \ - && rm bolty-listener-0.0.1.vsix - - -RUN mkdir -p /home/coder/.local/share/code-server/User \ - && echo '{"workbench.colorTheme": "Dark+", "workbench.preferredDarkColorTheme": "Dark+"}' > /home/coder/.local/share/code-server/User/settings.json - -CMD ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080", "--disable-telemetry", "/app"] diff --git a/mobile-magic/docker/Dockerfile.code-server-node b/mobile-magic/docker/Dockerfile.code-server-node new file mode 100644 index 0000000..b6e4731 --- /dev/null +++ b/mobile-magic/docker/Dockerfile.code-server-node @@ -0,0 +1,52 @@ +FROM codercom/code-server:4.96.4 + +# build arg for projectType +ARG projectType + +USER root +RUN apt-get update \ + && apt-get install -y curl \ + && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Revert to the code-server default user +USER coder +# Expose code-server's default port +EXPOSE 8080 + +# Cloning the repository and copy only the specified project based on projectType +RUN git clone https://github.com/code100x/mobile-magic.git /tmp/bolty-worker \ + && if [ "$projectType" = "mobile" ]; then \ + cp -r /tmp/bolty-worker/expo-base-app /app && rm -rf /tmp/bolty-worker/* && mv /app /tmp/bolty-worker/expo-base-app; \ + elif [ "$projectType" = "nextjs" ]; then \ + cp -r /tmp/bolty-worker/nextjs-base-app /app && rm -rf /tmp/bolty-worker/* && mv /app /tmp/bolty-worker/nextjs-base-app; \ + elif [ "$projectType" = "react" ]; then \ + cp -r /tmp/bolty-worker/react-base-app /app && rm -rf /tmp/bolty-worker/* && mv /app /tmp/bolty-worker/react-base-app; \ + else \ + echo "Invalid projectType."; exit 1; \ + fi \ + && mv /tmp/bolty-worker/* /app \ + && rm -rf /tmp/bolty-worker + +# install dependencies only for the selected project +WORKDIR /app +RUN npm install + +# downloading and installing extension] +RUN wget https://github.com/code100x/mobile-magic/raw/refs/heads/main/ext/bolty-listener-0.0.1.vsix +RUN code-server --install-extension bolty-listener-0.0.1.vsix + +USER root +RUN chown -R coder /app +USER coder + + +# Set default theme to dark +RUN mkdir -p /home/coder/.local/share/code-server/User +RUN echo '{"workbench.colorTheme": "Dark+", "workbench.preferredDarkColorTheme": "Dark+"}' > /home/coder/.local/share/code-server/User/settings.json + + +# Start code-server on container launch +CMD ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080", "--disable-telemetry", "/app"] diff --git a/mobile-magic/docker/Dockerfile.code-server-react-expo b/mobile-magic/docker/Dockerfile.code-server-react-expo deleted file mode 100644 index 9ff9f78..0000000 --- a/mobile-magic/docker/Dockerfile.code-server-react-expo +++ /dev/null @@ -1,32 +0,0 @@ -FROM codercom/code-server:4.96.4 - -USER root -RUN apt-get update \ - && apt-get install -y curl \ - && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ - && apt-get install -y nodejs \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -USER coder -EXPOSE 8080 - -# Clone repo and copy React Native template -RUN git clone https://github.com/code100x/mobile-magic.git /tmp/bolty-worker \ - && cp -r /tmp/bolty-worker/expo-base-app /app \ - && rm -rf /tmp/bolty-worker - - -WORKDIR /app -# RUN npm install //still update on dependency will rebuild so no benefit of pre-build just larger image size - - -RUN wget https://github.com/code100x/mobile-magic/raw/refs/heads/main/ext/bolty-listener-0.0.1.vsix \ - && code-server --install-extension bolty-listener-0.0.1.vsix \ - && rm bolty-listener-0.0.1.vsix - - -RUN mkdir -p /home/coder/.local/share/code-server/User \ - && echo '{"workbench.colorTheme": "Dark+", "workbench.preferredDarkColorTheme": "Dark+"}' > /home/coder/.local/share/code-server/User/settings.json - -CMD ["code-server", "--auth", "none", "--bind-addr", "0.0.0.0:8080", "--disable-telemetry", "/app"] diff --git a/mobile-magic/packages/db/index.ts b/mobile-magic/packages/db/index.ts index 82e3022..11bbdfe 100644 --- a/mobile-magic/packages/db/index.ts +++ b/mobile-magic/packages/db/index.ts @@ -1,4 +1,3 @@ import { PrismaClient } from "@prisma/client"; export const prismaClient = new PrismaClient(); - diff --git a/mobile-magic/packages/db/prisma/schema.prisma b/mobile-magic/packages/db/prisma/schema.prisma index c8f151b..8f32458 100644 --- a/mobile-magic/packages/db/prisma/schema.prisma +++ b/mobile-magic/packages/db/prisma/schema.prisma @@ -21,13 +21,14 @@ model User { } model Project { - id String @id @default(uuid()) + id String @id @default(uuid()) description String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt prompt Prompt[] actions Action[] type ProjectType @default(NEXTJS) + onS3 Boolean @default(false) userId String } @@ -38,14 +39,14 @@ enum ProjectType { } model Prompt { - id String @id @default(uuid()) + id String @id @default(uuid()) content String type PromptType - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - project Project @relation(fields: [projectId], references: [id]) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + project Project @relation(fields: [projectId], references: [id]) projectId String - actions Action[] + actions Action[] } model Action { @@ -63,5 +64,3 @@ enum PromptType { USER SYSTEM } - -