From 5b72f84951897be2088d124f11cfcf269baf3f94 Mon Sep 17 00:00:00 2001 From: Ishaan Dey Date: Mon, 13 May 2024 22:04:00 -0700 Subject: [PATCH] formatting --- backend/orchestrator/package.json | 6 +- backend/orchestrator/src/index.ts | 260 +++++++++++++++--------------- backend/server/src/utils.ts | 132 +++++++-------- frontend/lib/utils.ts | 70 ++++---- 4 files changed, 237 insertions(+), 231 deletions(-) diff --git a/backend/orchestrator/package.json b/backend/orchestrator/package.json index dda158b..6b1d158 100644 --- a/backend/orchestrator/package.json +++ b/backend/orchestrator/package.json @@ -4,7 +4,7 @@ "description": "", "main": "src/index.js", "scripts": { - "build": "npm i typescript && npx tsc", + "build": "npm i && npx tsc", "start": "node dist/index.js", "dev": "nodemon src/index.ts" }, @@ -16,10 +16,10 @@ "dotenv": "^16.4.5", "express": "^4.19.2", "yaml": "^2.4.2", - "zod": "^3.23.6", - "typescript": "^5.4.5" + "zod": "^3.23.6" }, "devDependencies": { + "typescript": "^5.4.5", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/node": "^20.12.8", diff --git a/backend/orchestrator/src/index.ts b/backend/orchestrator/src/index.ts index ef307eb..7c80eaf 100644 --- a/backend/orchestrator/src/index.ts +++ b/backend/orchestrator/src/index.ts @@ -1,159 +1,148 @@ -import express, { Express, Request, Response } from "express" -import dotenv from "dotenv" +import express, { Express, Request, Response } from "express"; +import dotenv from "dotenv"; -import fs from "fs" -import yaml from "yaml" -import path from "path" -import cors from "cors" +import fs from "fs"; +import yaml from "yaml"; +import path from "path"; +import cors from "cors"; import { KubeConfig, AppsV1Api, CoreV1Api, NetworkingV1Api, -} from "@kubernetes/client-node" -import { z } from "zod" - -const app = express() -const port = process.env.PORT || 4001 -app.use(express.json()) -dotenv.config() +} from "@kubernetes/client-node"; +import { z } from "zod"; +const app = express(); +const port = process.env.PORT || 4001; +app.use(express.json()); +dotenv.config(); // const corsOptions = { // origin: ['http://localhost:3000', 'https://s.ishaand.com', 'http://localhost:4000', /\.ws\.ishaand\.com$/], // } // app.use(cors(corsOptions)) -app.use(cors()) +app.use(cors()); -const kubeconfig = new KubeConfig() -if (process.env.NODE_ENV !== "deployment") { - kubeconfig.loadFromOptions({ - clusters: [ - { - name: 'gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster', - server: process.env.GKE_CLUSTER_SERVER!, - caData: process.env.GKE_CLUSTER_CA_DATA, - } - ], - users: [ - { - name: 'gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster', - exec: { - apiVersion: 'client.authentication.k8s.io/v1beta1', - command: 'gke-gcloud-auth-plugin', - installHint: 'Install gke-gcloud-auth-plugin for use with kubectl by following https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl#install_plugin', - interactiveMode: 'IfAvailable', - provideClusterInfo: true - } - } - ], - contexts: [ - { - name: 'gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster', - cluster: 'gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster', - user: 'gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster' - } - ], - currentContext: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster" - }); -} -kubeconfig.loadFromDefault() +const kubeconfig = new KubeConfig(); +kubeconfig.loadFromOptions({ + clusters: [ + { + name: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster", + server: process.env.GKE_CLUSTER_SERVER!, + caData: process.env.GKE_CLUSTER_CA_DATA, + }, + ], + users: [ + { + name: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster", + exec: { + apiVersion: "client.authentication.k8s.io/v1beta1", + command: "gke-gcloud-auth-plugin", + installHint: + "Install gke-gcloud-auth-plugin for use with kubectl by following https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl#install_plugin", + interactiveMode: "IfAvailable", + provideClusterInfo: true, + }, + }, + ], + contexts: [ + { + name: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster", + cluster: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster", + user: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster", + }, + ], + currentContext: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster", +}); -const appsV1Api = kubeconfig.makeApiClient(AppsV1Api) -const coreV1Api = kubeconfig.makeApiClient(CoreV1Api) -const networkingV1Api = kubeconfig.makeApiClient(NetworkingV1Api) +const appsV1Api = kubeconfig.makeApiClient(AppsV1Api); +const coreV1Api = kubeconfig.makeApiClient(CoreV1Api); +const networkingV1Api = kubeconfig.makeApiClient(NetworkingV1Api); const readAndParseKubeYaml = ( filePath: string, sandboxId: string ): Array => { - const fileContent = fs.readFileSync(filePath, "utf8") + const fileContent = fs.readFileSync(filePath, "utf8"); const docs = yaml.parseAllDocuments(fileContent).map((doc) => { - let docString = doc.toString() + let docString = doc.toString(); - const regex = new RegExp(``, "g") - docString = docString.replace(regex, sandboxId) + const regex = new RegExp(``, "g"); + docString = docString.replace(regex, sandboxId); if (!process.env.CF_API_TOKEN) { - throw new Error("CF_API_TOKEN is not defined") + throw new Error("CF_API_TOKEN is not defined"); } - const regexEnv1 = new RegExp(``, "g") - docString = docString.replace(regexEnv1, process.env.CF_API_TOKEN) + const regexEnv1 = new RegExp(``, "g"); + docString = docString.replace(regexEnv1, process.env.CF_API_TOKEN); if (!process.env.CF_USER_ID) { - throw new Error("CF_USER_ID is not defined") + throw new Error("CF_USER_ID is not defined"); } - const regexEnv2 = new RegExp(``, "g") - docString = docString.replace(regexEnv2, process.env.CF_USER_ID) + const regexEnv2 = new RegExp(``, "g"); + docString = docString.replace(regexEnv2, process.env.CF_USER_ID); - return yaml.parse(docString) - }) - return docs -} + return yaml.parse(docString); + }); + return docs; +}; const dataSchema = z.object({ userId: z.string(), sandboxId: z.string(), -}) +}); -const namespace = "ingress-nginx" +const namespace = "ingress-nginx"; + +app.get("/", async (req, res) => { + res.status(200).send({ message: "Orchestrator" }); +}); app.post("/test", async (req, res) => { - const pods = await coreV1Api.listNamespacedPod(namespace) - res.status(200).send({ pods: pods.body.items.map(item => item?.metadata?.generateName), message: "Orchestrator is up and running." }) - // res.status(200).send({ message: "Orchestrator is up and running." }) -}) + const pods = await coreV1Api.listNamespacedPod(namespace); + res.status(200).send({ + pods: pods.body.items.map((item) => item?.metadata?.generateName), + message: "Orchestrator is up and running.", + }); +}); app.post("/start", async (req, res) => { - const { sandboxId } = dataSchema.parse(req.body) - - // async function main() { - // const client = new container.v1.ClusterManagerClient(); - - // async function quickstart() { - // const zone = 'us-central1-a'; - // const projectId = await client.getProjectId(); - // const request = { - // projectId: projectId, - // zone: zone, - // }; - - // const [response] = await client.listClusters(request); - // console.log('Clusters: ', response); - // } - - // quickstart(); - // } - - // main().catch(console.error); + const { sandboxId } = dataSchema.parse(req.body); try { + console.log("Creating resources for sandbox", sandboxId); - console.log("Creating resources for sandbox", sandboxId) - const kubeManifests = readAndParseKubeYaml( path.join(__dirname, "../service.yaml"), sandboxId - ) + ); async function resourceExists(api: any, getMethod: string, name: string) { try { - await api[getMethod](name, namespace) - return true + await api[getMethod](name, namespace); + return true; } catch (e: any) { if (e.response && e.response.statusCode === 404) { - console.log("Resource does not exist.", e.response.body.message, e.response.body.details) - return false + console.log( + "Resource does not exist.", + e.response.body.message, + e.response.body.details + ); + return false; } - throw e + throw e; } } const createResource = async (api: any, method: string, manifest: any) => { - const { kind, metadata: { name } } = manifest; - if (!(await resourceExists(api, 'readNamespaced' + kind, name))) { - await api['createNamespaced' + kind](namespace, manifest); + const { + kind, + metadata: { name }, + } = manifest; + if (!(await resourceExists(api, "readNamespaced" + kind, name))) { + await api["createNamespaced" + kind](namespace, manifest); console.log(`Created ${kind.toLowerCase()}`, name); } else { console.log(`${kind} ${name} already exists.`); @@ -161,74 +150,77 @@ app.post("/start", async (req, res) => { }; const promises = kubeManifests.map(async (manifest) => { - const { kind, metadata: { name } } = manifest + const { + kind, + metadata: { name }, + } = manifest; - console.log("Kind:", kind) + console.log("Kind:", kind); switch (manifest.kind) { - case 'Deployment': - return createResource(appsV1Api, 'Deployment', manifest); - case 'Service': - return createResource(coreV1Api, 'Service', manifest); - case 'Ingress': - return createResource(networkingV1Api, 'Ingress', manifest); + case "Deployment": + return createResource(appsV1Api, "Deployment", manifest); + case "Service": + return createResource(coreV1Api, "Service", manifest); + case "Ingress": + return createResource(networkingV1Api, "Ingress", manifest); default: console.error("Unsupported kind:", manifest.kind); return Promise.reject("Unsupported kind: " + manifest.kind); } - }) + }); - await Promise.all(promises) + await Promise.all(promises); - console.log("All done!") - res.status(200).send({ message: "Resources created." }) + console.log("All done!"); + res.status(200).send({ message: "Resources created." }); } catch (error: any) { - const body = error.response.body - console.log("Failed to create resources", error) + const body = error.response.body; + console.log("Failed to create resources", error); if (body.code === 409) { - return res.status(200).send({ message: "Resource already exists." }) + return res.status(200).send({ message: "Resource already exists." }); } - res.status(500).send({ message: "Failed to create resources." }) + res.status(500).send({ message: "Failed to create resources." }); } -}) +}); app.post("/stop", async (req, res) => { - const { sandboxId } = dataSchema.parse(req.body) - console.log("Deleting resources for sandbox", sandboxId) + const { sandboxId } = dataSchema.parse(req.body); + console.log("Deleting resources for sandbox", sandboxId); try { const kubeManifests = readAndParseKubeYaml( path.join(__dirname, "../service.yaml"), sandboxId - ) + ); const promises = kubeManifests.map(async (manifest) => { if (manifest.kind === "Deployment") await appsV1Api.deleteNamespacedDeployment( manifest.metadata?.name || "", namespace - ) + ); else if (manifest.kind === "Service") await coreV1Api.deleteNamespacedService( manifest.metadata?.name || "", namespace - ) + ); else if (manifest.kind === "Ingress") await networkingV1Api.deleteNamespacedIngress( manifest.metadata?.name || "", namespace - ) - }) + ); + }); - await Promise.all(promises) - - res.status(200).send({ message: "Resources deleted." }) + await Promise.all(promises); + + res.status(200).send({ message: "Resources deleted." }); } catch (error) { - console.log("Failed to delete resources", error) - res.status(500).send({ message: "Failed to delete resources." }) + console.log("Failed to delete resources", error); + res.status(500).send({ message: "Failed to delete resources." }); } -}) +}); app.listen(port, () => { - console.log(`Listening on port: ${port}`) -}) + console.log(`Listening on port: ${port}`); +}); diff --git a/backend/server/src/utils.ts b/backend/server/src/utils.ts index ef932f0..94fabc8 100644 --- a/backend/server/src/utils.ts +++ b/backend/server/src/utils.ts @@ -1,4 +1,4 @@ -import e from "cors" +import e from "cors"; import { R2FileBody, R2Files, @@ -7,55 +7,55 @@ import { TFileData, TFolder, User, -} from "./types" +} from "./types"; export const getSandboxFiles = async (id: string) => { const res = await fetch( `https://storage.ishaan1013.workers.dev/api?sandboxId=${id}` - ) - const data: R2Files = await res.json() + ); + const data: R2Files = await res.json(); - const paths = data.objects.map((obj) => obj.key) - const processedFiles = await processFiles(paths, id) - return processedFiles -} + const paths = data.objects.map((obj) => obj.key); + const processedFiles = await processFiles(paths, id); + return processedFiles; +}; export const getFolder = async (folderId: string) => { const res = await fetch( `https://storage.ishaan1013.workers.dev/api?folderId=${folderId}` - ) - const data: R2Files = await res.json() + ); + const data: R2Files = await res.json(); - return data.objects.map((obj) => obj.key) -} + return data.objects.map((obj) => obj.key); +}; const processFiles = async (paths: string[], id: string) => { - const root: TFolder = { id: "/", type: "folder", name: "/", children: [] } - const fileData: TFileData[] = [] + const root: TFolder = { id: "/", type: "folder", name: "/", children: [] }; + const fileData: TFileData[] = []; paths.forEach((path) => { - const allParts = path.split("/") + const allParts = path.split("/"); if (allParts[1] !== id) { - return + return; } - const parts = allParts.slice(2) - let current: TFolder = root + const parts = allParts.slice(2); + let current: TFolder = root; for (let i = 0; i < parts.length; i++) { - const part = parts[i] - const isFile = i === parts.length - 1 && part.includes(".") - const existing = current.children.find((child) => child.name === part) + const part = parts[i]; + const isFile = i === parts.length - 1 && part.includes("."); + const existing = current.children.find((child) => child.name === part); if (existing) { if (!isFile) { - current = existing as TFolder + current = existing as TFolder; } } else { if (isFile) { - const file: TFile = { id: path, type: "file", name: part } - current.children.push(file) - fileData.push({ id: path, data: "" }) + const file: TFile = { id: path, type: "file", name: part }; + current.children.push(file); + fileData.push({ id: path, data: "" }); } else { const folder: TFolder = { // id: path, // todo: wrong id. for example, folder "src" ID is: projects/a7vgttfqbgy403ratp7du3ln/src/App.css @@ -63,38 +63,38 @@ const processFiles = async (paths: string[], id: string) => { type: "folder", name: part, children: [], - } - current.children.push(folder) - current = folder + }; + current.children.push(folder); + current = folder; } } } - }) + }); await Promise.all( fileData.map(async (file) => { - const data = await fetchFileContent(file.id) - file.data = data + const data = await fetchFileContent(file.id); + file.data = data; }) - ) + ); return { files: root.children, fileData, - } -} + }; +}; const fetchFileContent = async (fileId: string): Promise => { try { const fileRes = await fetch( `https://storage.ishaan1013.workers.dev/api?fileId=${fileId}` - ) - return await fileRes.text() + ); + return await fileRes.text(); } catch (error) { - console.error("ERROR fetching file:", error) - return "" + console.error("ERROR fetching file:", error); + return ""; } -} +}; export const createFile = async (fileId: string) => { const res = await fetch(`https://storage.ishaan1013.workers.dev/api`, { @@ -103,9 +103,9 @@ export const createFile = async (fileId: string) => { "Content-Type": "application/json", }, body: JSON.stringify({ fileId }), - }) - return res.ok -} + }); + return res.ok; +}; export const renameFile = async ( fileId: string, @@ -118,9 +118,9 @@ export const renameFile = async ( "Content-Type": "application/json", }, body: JSON.stringify({ fileId, newFileId, data }), - }) - return res.ok -} + }); + return res.ok; +}; export const saveFile = async (fileId: string, data: string) => { const res = await fetch(`https://storage.ishaan1013.workers.dev/api/save`, { @@ -129,9 +129,9 @@ export const saveFile = async (fileId: string, data: string) => { "Content-Type": "application/json", }, body: JSON.stringify({ fileId, data }), - }) - return res.ok -} + }); + return res.ok; +}; export const deleteFile = async (fileId: string) => { const res = await fetch(`https://storage.ishaan1013.workers.dev/api`, { @@ -140,16 +140,16 @@ export const deleteFile = async (fileId: string) => { "Content-Type": "application/json", }, body: JSON.stringify({ fileId }), - }) - return res.ok -} + }); + return res.ok; +}; export const getProjectSize = async (id: string) => { const res = await fetch( `https://storage.ishaan1013.workers.dev/api/size?sandboxId=${id}` - ) - return (await res.json()).size -} + ); + return (await res.json()).size; +}; export const generateCode = async ({ fileName, @@ -157,10 +157,10 @@ export const generateCode = async ({ line, instructions, }: { - fileName: string - code: string - line: number - instructions: string + fileName: string; + code: string; + line: number; + instructions: string; }) => { return await fetch( `https://api.cloudflare.com/client/v4/accounts/${process.env.CF_USER_ID}/ai/run/@cf/meta/llama-3-8b-instruct`, @@ -194,21 +194,21 @@ ${code}`, ], }), } - ) -} + ); +}; export const stopServer = async (sandboxId: string, userId: string) => { - const res = await fetch("https://sylvan-epoch-422219-f9.uc.r.appspot.com/stop", { + const res = await fetch("http://localhost:4001/stop", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ sandboxId, - userId + userId, }), - }) - const data = await res.json() + }); + const data = await res.json(); - return data -} \ No newline at end of file + return data; +}; diff --git a/frontend/lib/utils.ts b/frontend/lib/utils.ts index 9e66b9f..3886ffc 100644 --- a/frontend/lib/utils.ts +++ b/frontend/lib/utils.ts @@ -1,21 +1,20 @@ -import { type ClassValue, clsx } from "clsx" +import { type ClassValue, clsx } from "clsx"; // import { toast } from "sonner" -import { twMerge } from "tailwind-merge" -import { Sandbox, TFile, TFolder } from "./types" - +import { twMerge } from "tailwind-merge"; +import { Sandbox, TFile, TFolder } from "./types"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); } export function processFileType(file: string) { - const ending = file.split(".").pop() + const ending = file.split(".").pop(); - if (ending === "ts" || ending === "tsx") return "typescript" - if (ending === "js" || ending === "jsx") return "javascript" + if (ending === "ts" || ending === "tsx") return "typescript"; + if (ending === "js" || ending === "jsx") return "javascript"; - if (ending) return ending - return "plaintext" + if (ending) return ending; + return "plaintext"; } export function validateName( @@ -24,7 +23,7 @@ export function validateName( type: "file" | "folder" ) { if (newName === oldName || newName.length === 0) { - return { status: false, message: "" } + return { status: false, message: "" }; } if ( newName.includes("/") || @@ -33,12 +32,17 @@ export function validateName( (type === "file" && !newName.includes(".")) || (type === "folder" && newName.includes(".")) ) { - return { status: false, message: "Invalid file name." } + return { status: false, message: "Invalid file name." }; } - return { status: true, message: "" } + return { status: true, message: "" }; } -export function addNew(name: string, type: "file" | "folder", setFiles: React.Dispatch>, sandboxData: Sandbox) { +export function addNew( + name: string, + type: "file" | "folder", + setFiles: React.Dispatch>, + sandboxData: Sandbox +) { if (type === "file") { setFiles((prev) => [ ...prev, @@ -46,34 +50,44 @@ export function addNew(name: string, type: "file" | "folder", setFiles: React.Di ]); } else { console.log("adding folder"); - setFiles(prev => [...prev, { id: `projects/${sandboxData.id}/${name}`, name, type: "folder", children: [] }]) + setFiles((prev) => [ + ...prev, + { + id: `projects/${sandboxData.id}/${name}`, + name, + type: "folder", + children: [], + }, + ]); } } -export async function startServer(sandboxId: string, userId: string, callback: (success: boolean) => void) { +export async function startServer( + sandboxId: string, + userId: string, + callback: (success: boolean) => void +) { try { - const res = await fetch("https://sylvan-epoch-422219-f9.uc.r.appspot.com/start", { + const res = await fetch("http://localhost:4001/start", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ sandboxId, - userId + userId, }), - }) + }); if (res.status !== 200) { - console.error("Failed to start server", res) - callback(false) + console.error("Failed to start server", res); + callback(false); } - callback(true) - + callback(true); } catch (error) { - console.error("Failed to start server", error) - - callback(false) - } + console.error("Failed to start server", error); -} \ No newline at end of file + callback(false); + } +}