formatting
This commit is contained in:
parent
fb1b95a157
commit
5b72f84951
@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm i typescript && npx tsc",
|
"build": "npm i && npx tsc",
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/index.js",
|
||||||
"dev": "nodemon src/index.ts"
|
"dev": "nodemon src/index.ts"
|
||||||
},
|
},
|
||||||
@ -16,10 +16,10 @@
|
|||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"yaml": "^2.4.2",
|
"yaml": "^2.4.2",
|
||||||
"zod": "^3.23.6",
|
"zod": "^3.23.6"
|
||||||
"typescript": "^5.4.5"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"typescript": "^5.4.5",
|
||||||
"@types/cors": "^2.8.17",
|
"@types/cors": "^2.8.17",
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/node": "^20.12.8",
|
"@types/node": "^20.12.8",
|
||||||
|
@ -1,159 +1,148 @@
|
|||||||
import express, { Express, Request, Response } from "express"
|
import express, { Express, Request, Response } from "express";
|
||||||
import dotenv from "dotenv"
|
import dotenv from "dotenv";
|
||||||
|
|
||||||
import fs from "fs"
|
import fs from "fs";
|
||||||
import yaml from "yaml"
|
import yaml from "yaml";
|
||||||
import path from "path"
|
import path from "path";
|
||||||
import cors from "cors"
|
import cors from "cors";
|
||||||
import {
|
import {
|
||||||
KubeConfig,
|
KubeConfig,
|
||||||
AppsV1Api,
|
AppsV1Api,
|
||||||
CoreV1Api,
|
CoreV1Api,
|
||||||
NetworkingV1Api,
|
NetworkingV1Api,
|
||||||
} from "@kubernetes/client-node"
|
} from "@kubernetes/client-node";
|
||||||
import { z } from "zod"
|
import { z } from "zod";
|
||||||
|
|
||||||
const app = express()
|
|
||||||
const port = process.env.PORT || 4001
|
|
||||||
app.use(express.json())
|
|
||||||
dotenv.config()
|
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = process.env.PORT || 4001;
|
||||||
|
app.use(express.json());
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
// const corsOptions = {
|
// const corsOptions = {
|
||||||
// origin: ['http://localhost:3000', 'https://s.ishaand.com', 'http://localhost:4000', /\.ws\.ishaand\.com$/],
|
// origin: ['http://localhost:3000', 'https://s.ishaand.com', 'http://localhost:4000', /\.ws\.ishaand\.com$/],
|
||||||
// }
|
// }
|
||||||
// app.use(cors(corsOptions))
|
// app.use(cors(corsOptions))
|
||||||
|
|
||||||
app.use(cors())
|
app.use(cors());
|
||||||
|
|
||||||
const kubeconfig = new KubeConfig()
|
const kubeconfig = new KubeConfig();
|
||||||
if (process.env.NODE_ENV !== "deployment") {
|
kubeconfig.loadFromOptions({
|
||||||
kubeconfig.loadFromOptions({
|
clusters: [
|
||||||
clusters: [
|
{
|
||||||
{
|
name: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster",
|
||||||
name: 'gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster',
|
server: process.env.GKE_CLUSTER_SERVER!,
|
||||||
server: process.env.GKE_CLUSTER_SERVER!,
|
caData: process.env.GKE_CLUSTER_CA_DATA,
|
||||||
caData: process.env.GKE_CLUSTER_CA_DATA,
|
},
|
||||||
}
|
],
|
||||||
],
|
users: [
|
||||||
users: [
|
{
|
||||||
{
|
name: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster",
|
||||||
name: 'gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster',
|
exec: {
|
||||||
exec: {
|
apiVersion: "client.authentication.k8s.io/v1beta1",
|
||||||
apiVersion: 'client.authentication.k8s.io/v1beta1',
|
command: "gke-gcloud-auth-plugin",
|
||||||
command: 'gke-gcloud-auth-plugin',
|
installHint:
|
||||||
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',
|
"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',
|
interactiveMode: "IfAvailable",
|
||||||
provideClusterInfo: true
|
provideClusterInfo: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
contexts: [
|
contexts: [
|
||||||
{
|
{
|
||||||
name: 'gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster',
|
name: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster",
|
||||||
cluster: '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'
|
user: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
currentContext: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster"
|
currentContext: "gke_sylvan-epoch-422219-f9_us-central1_sandbox-cluster",
|
||||||
});
|
});
|
||||||
}
|
|
||||||
kubeconfig.loadFromDefault()
|
|
||||||
|
|
||||||
const appsV1Api = kubeconfig.makeApiClient(AppsV1Api)
|
const appsV1Api = kubeconfig.makeApiClient(AppsV1Api);
|
||||||
const coreV1Api = kubeconfig.makeApiClient(CoreV1Api)
|
const coreV1Api = kubeconfig.makeApiClient(CoreV1Api);
|
||||||
const networkingV1Api = kubeconfig.makeApiClient(NetworkingV1Api)
|
const networkingV1Api = kubeconfig.makeApiClient(NetworkingV1Api);
|
||||||
|
|
||||||
const readAndParseKubeYaml = (
|
const readAndParseKubeYaml = (
|
||||||
filePath: string,
|
filePath: string,
|
||||||
sandboxId: string
|
sandboxId: string
|
||||||
): Array<any> => {
|
): Array<any> => {
|
||||||
const fileContent = fs.readFileSync(filePath, "utf8")
|
const fileContent = fs.readFileSync(filePath, "utf8");
|
||||||
const docs = yaml.parseAllDocuments(fileContent).map((doc) => {
|
const docs = yaml.parseAllDocuments(fileContent).map((doc) => {
|
||||||
let docString = doc.toString()
|
let docString = doc.toString();
|
||||||
|
|
||||||
const regex = new RegExp(`<SANDBOX>`, "g")
|
const regex = new RegExp(`<SANDBOX>`, "g");
|
||||||
docString = docString.replace(regex, sandboxId)
|
docString = docString.replace(regex, sandboxId);
|
||||||
|
|
||||||
if (!process.env.CF_API_TOKEN) {
|
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(`<CF_API_TOKEN>`, "g")
|
const regexEnv1 = new RegExp(`<CF_API_TOKEN>`, "g");
|
||||||
docString = docString.replace(regexEnv1, process.env.CF_API_TOKEN)
|
docString = docString.replace(regexEnv1, process.env.CF_API_TOKEN);
|
||||||
|
|
||||||
if (!process.env.CF_USER_ID) {
|
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(`<CF_USER_ID>`, "g")
|
const regexEnv2 = new RegExp(`<CF_USER_ID>`, "g");
|
||||||
docString = docString.replace(regexEnv2, process.env.CF_USER_ID)
|
docString = docString.replace(regexEnv2, process.env.CF_USER_ID);
|
||||||
|
|
||||||
return yaml.parse(docString)
|
return yaml.parse(docString);
|
||||||
})
|
});
|
||||||
return docs
|
return docs;
|
||||||
}
|
};
|
||||||
|
|
||||||
const dataSchema = z.object({
|
const dataSchema = z.object({
|
||||||
userId: z.string(),
|
userId: z.string(),
|
||||||
sandboxId: 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) => {
|
app.post("/test", async (req, res) => {
|
||||||
const pods = await coreV1Api.listNamespacedPod(namespace)
|
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({
|
||||||
// res.status(200).send({ message: "Orchestrator is up and running." })
|
pods: pods.body.items.map((item) => item?.metadata?.generateName),
|
||||||
})
|
message: "Orchestrator is up and running.",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.post("/start", async (req, res) => {
|
app.post("/start", async (req, res) => {
|
||||||
const { sandboxId } = dataSchema.parse(req.body)
|
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);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log("Creating resources for sandbox", sandboxId);
|
||||||
|
|
||||||
console.log("Creating resources for sandbox", sandboxId)
|
|
||||||
|
|
||||||
const kubeManifests = readAndParseKubeYaml(
|
const kubeManifests = readAndParseKubeYaml(
|
||||||
path.join(__dirname, "../service.yaml"),
|
path.join(__dirname, "../service.yaml"),
|
||||||
sandboxId
|
sandboxId
|
||||||
)
|
);
|
||||||
|
|
||||||
async function resourceExists(api: any, getMethod: string, name: string) {
|
async function resourceExists(api: any, getMethod: string, name: string) {
|
||||||
try {
|
try {
|
||||||
await api[getMethod](name, namespace)
|
await api[getMethod](name, namespace);
|
||||||
return true
|
return true;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.response && e.response.statusCode === 404) {
|
if (e.response && e.response.statusCode === 404) {
|
||||||
console.log("Resource does not exist.", e.response.body.message, e.response.body.details)
|
console.log(
|
||||||
return false
|
"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 createResource = async (api: any, method: string, manifest: any) => {
|
||||||
const { kind, metadata: { name } } = manifest;
|
const {
|
||||||
if (!(await resourceExists(api, 'readNamespaced' + kind, name))) {
|
kind,
|
||||||
await api['createNamespaced' + kind](namespace, manifest);
|
metadata: { name },
|
||||||
|
} = manifest;
|
||||||
|
if (!(await resourceExists(api, "readNamespaced" + kind, name))) {
|
||||||
|
await api["createNamespaced" + kind](namespace, manifest);
|
||||||
console.log(`Created ${kind.toLowerCase()}`, name);
|
console.log(`Created ${kind.toLowerCase()}`, name);
|
||||||
} else {
|
} else {
|
||||||
console.log(`${kind} ${name} already exists.`);
|
console.log(`${kind} ${name} already exists.`);
|
||||||
@ -161,74 +150,77 @@ app.post("/start", async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const promises = kubeManifests.map(async (manifest) => {
|
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) {
|
switch (manifest.kind) {
|
||||||
case 'Deployment':
|
case "Deployment":
|
||||||
return createResource(appsV1Api, 'Deployment', manifest);
|
return createResource(appsV1Api, "Deployment", manifest);
|
||||||
case 'Service':
|
case "Service":
|
||||||
return createResource(coreV1Api, 'Service', manifest);
|
return createResource(coreV1Api, "Service", manifest);
|
||||||
case 'Ingress':
|
case "Ingress":
|
||||||
return createResource(networkingV1Api, 'Ingress', manifest);
|
return createResource(networkingV1Api, "Ingress", manifest);
|
||||||
default:
|
default:
|
||||||
console.error("Unsupported kind:", manifest.kind);
|
console.error("Unsupported kind:", manifest.kind);
|
||||||
return Promise.reject("Unsupported kind: " + manifest.kind);
|
return Promise.reject("Unsupported kind: " + manifest.kind);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises);
|
||||||
|
|
||||||
console.log("All done!")
|
console.log("All done!");
|
||||||
res.status(200).send({ message: "Resources created." })
|
res.status(200).send({ message: "Resources created." });
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const body = error.response.body
|
const body = error.response.body;
|
||||||
console.log("Failed to create resources", error)
|
console.log("Failed to create resources", error);
|
||||||
|
|
||||||
if (body.code === 409) {
|
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) => {
|
app.post("/stop", async (req, res) => {
|
||||||
const { sandboxId } = dataSchema.parse(req.body)
|
const { sandboxId } = dataSchema.parse(req.body);
|
||||||
console.log("Deleting resources for sandbox", sandboxId)
|
console.log("Deleting resources for sandbox", sandboxId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const kubeManifests = readAndParseKubeYaml(
|
const kubeManifests = readAndParseKubeYaml(
|
||||||
path.join(__dirname, "../service.yaml"),
|
path.join(__dirname, "../service.yaml"),
|
||||||
sandboxId
|
sandboxId
|
||||||
)
|
);
|
||||||
const promises = kubeManifests.map(async (manifest) => {
|
const promises = kubeManifests.map(async (manifest) => {
|
||||||
if (manifest.kind === "Deployment")
|
if (manifest.kind === "Deployment")
|
||||||
await appsV1Api.deleteNamespacedDeployment(
|
await appsV1Api.deleteNamespacedDeployment(
|
||||||
manifest.metadata?.name || "",
|
manifest.metadata?.name || "",
|
||||||
namespace
|
namespace
|
||||||
)
|
);
|
||||||
else if (manifest.kind === "Service")
|
else if (manifest.kind === "Service")
|
||||||
await coreV1Api.deleteNamespacedService(
|
await coreV1Api.deleteNamespacedService(
|
||||||
manifest.metadata?.name || "",
|
manifest.metadata?.name || "",
|
||||||
namespace
|
namespace
|
||||||
)
|
);
|
||||||
else if (manifest.kind === "Ingress")
|
else if (manifest.kind === "Ingress")
|
||||||
await networkingV1Api.deleteNamespacedIngress(
|
await networkingV1Api.deleteNamespacedIngress(
|
||||||
manifest.metadata?.name || "",
|
manifest.metadata?.name || "",
|
||||||
namespace
|
namespace
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises);
|
||||||
|
|
||||||
res.status(200).send({ message: "Resources deleted." })
|
res.status(200).send({ message: "Resources deleted." });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Failed to delete resources", error)
|
console.log("Failed to delete resources", error);
|
||||||
res.status(500).send({ message: "Failed to delete resources." })
|
res.status(500).send({ message: "Failed to delete resources." });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Listening on port: ${port}`)
|
console.log(`Listening on port: ${port}`);
|
||||||
})
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import e from "cors"
|
import e from "cors";
|
||||||
import {
|
import {
|
||||||
R2FileBody,
|
R2FileBody,
|
||||||
R2Files,
|
R2Files,
|
||||||
@ -7,55 +7,55 @@ import {
|
|||||||
TFileData,
|
TFileData,
|
||||||
TFolder,
|
TFolder,
|
||||||
User,
|
User,
|
||||||
} from "./types"
|
} from "./types";
|
||||||
|
|
||||||
export const getSandboxFiles = async (id: string) => {
|
export const getSandboxFiles = async (id: string) => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`https://storage.ishaan1013.workers.dev/api?sandboxId=${id}`
|
`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 paths = data.objects.map((obj) => obj.key);
|
||||||
const processedFiles = await processFiles(paths, id)
|
const processedFiles = await processFiles(paths, id);
|
||||||
return processedFiles
|
return processedFiles;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getFolder = async (folderId: string) => {
|
export const getFolder = async (folderId: string) => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`https://storage.ishaan1013.workers.dev/api?folderId=${folderId}`
|
`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 processFiles = async (paths: string[], id: string) => {
|
||||||
const root: TFolder = { id: "/", type: "folder", name: "/", children: [] }
|
const root: TFolder = { id: "/", type: "folder", name: "/", children: [] };
|
||||||
const fileData: TFileData[] = []
|
const fileData: TFileData[] = [];
|
||||||
|
|
||||||
paths.forEach((path) => {
|
paths.forEach((path) => {
|
||||||
const allParts = path.split("/")
|
const allParts = path.split("/");
|
||||||
if (allParts[1] !== id) {
|
if (allParts[1] !== id) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parts = allParts.slice(2)
|
const parts = allParts.slice(2);
|
||||||
let current: TFolder = root
|
let current: TFolder = root;
|
||||||
|
|
||||||
for (let i = 0; i < parts.length; i++) {
|
for (let i = 0; i < parts.length; i++) {
|
||||||
const part = parts[i]
|
const part = parts[i];
|
||||||
const isFile = i === parts.length - 1 && part.includes(".")
|
const isFile = i === parts.length - 1 && part.includes(".");
|
||||||
const existing = current.children.find((child) => child.name === part)
|
const existing = current.children.find((child) => child.name === part);
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
if (!isFile) {
|
if (!isFile) {
|
||||||
current = existing as TFolder
|
current = existing as TFolder;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isFile) {
|
if (isFile) {
|
||||||
const file: TFile = { id: path, type: "file", name: part }
|
const file: TFile = { id: path, type: "file", name: part };
|
||||||
current.children.push(file)
|
current.children.push(file);
|
||||||
fileData.push({ id: path, data: "" })
|
fileData.push({ id: path, data: "" });
|
||||||
} else {
|
} else {
|
||||||
const folder: TFolder = {
|
const folder: TFolder = {
|
||||||
// id: path, // todo: wrong id. for example, folder "src" ID is: projects/a7vgttfqbgy403ratp7du3ln/src/App.css
|
// 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",
|
type: "folder",
|
||||||
name: part,
|
name: part,
|
||||||
children: [],
|
children: [],
|
||||||
}
|
};
|
||||||
current.children.push(folder)
|
current.children.push(folder);
|
||||||
current = folder
|
current = folder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
fileData.map(async (file) => {
|
fileData.map(async (file) => {
|
||||||
const data = await fetchFileContent(file.id)
|
const data = await fetchFileContent(file.id);
|
||||||
file.data = data
|
file.data = data;
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
files: root.children,
|
files: root.children,
|
||||||
fileData,
|
fileData,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const fetchFileContent = async (fileId: string): Promise<string> => {
|
const fetchFileContent = async (fileId: string): Promise<string> => {
|
||||||
try {
|
try {
|
||||||
const fileRes = await fetch(
|
const fileRes = await fetch(
|
||||||
`https://storage.ishaan1013.workers.dev/api?fileId=${fileId}`
|
`https://storage.ishaan1013.workers.dev/api?fileId=${fileId}`
|
||||||
)
|
);
|
||||||
return await fileRes.text()
|
return await fileRes.text();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("ERROR fetching file:", error)
|
console.error("ERROR fetching file:", error);
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export const createFile = async (fileId: string) => {
|
export const createFile = async (fileId: string) => {
|
||||||
const res = await fetch(`https://storage.ishaan1013.workers.dev/api`, {
|
const res = await fetch(`https://storage.ishaan1013.workers.dev/api`, {
|
||||||
@ -103,9 +103,9 @@ export const createFile = async (fileId: string) => {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ fileId }),
|
body: JSON.stringify({ fileId }),
|
||||||
})
|
});
|
||||||
return res.ok
|
return res.ok;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const renameFile = async (
|
export const renameFile = async (
|
||||||
fileId: string,
|
fileId: string,
|
||||||
@ -118,9 +118,9 @@ export const renameFile = async (
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ fileId, newFileId, data }),
|
body: JSON.stringify({ fileId, newFileId, data }),
|
||||||
})
|
});
|
||||||
return res.ok
|
return res.ok;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const saveFile = async (fileId: string, data: string) => {
|
export const saveFile = async (fileId: string, data: string) => {
|
||||||
const res = await fetch(`https://storage.ishaan1013.workers.dev/api/save`, {
|
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",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ fileId, data }),
|
body: JSON.stringify({ fileId, data }),
|
||||||
})
|
});
|
||||||
return res.ok
|
return res.ok;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const deleteFile = async (fileId: string) => {
|
export const deleteFile = async (fileId: string) => {
|
||||||
const res = await fetch(`https://storage.ishaan1013.workers.dev/api`, {
|
const res = await fetch(`https://storage.ishaan1013.workers.dev/api`, {
|
||||||
@ -140,16 +140,16 @@ export const deleteFile = async (fileId: string) => {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ fileId }),
|
body: JSON.stringify({ fileId }),
|
||||||
})
|
});
|
||||||
return res.ok
|
return res.ok;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getProjectSize = async (id: string) => {
|
export const getProjectSize = async (id: string) => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`https://storage.ishaan1013.workers.dev/api/size?sandboxId=${id}`
|
`https://storage.ishaan1013.workers.dev/api/size?sandboxId=${id}`
|
||||||
)
|
);
|
||||||
return (await res.json()).size
|
return (await res.json()).size;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const generateCode = async ({
|
export const generateCode = async ({
|
||||||
fileName,
|
fileName,
|
||||||
@ -157,10 +157,10 @@ export const generateCode = async ({
|
|||||||
line,
|
line,
|
||||||
instructions,
|
instructions,
|
||||||
}: {
|
}: {
|
||||||
fileName: string
|
fileName: string;
|
||||||
code: string
|
code: string;
|
||||||
line: number
|
line: number;
|
||||||
instructions: string
|
instructions: string;
|
||||||
}) => {
|
}) => {
|
||||||
return await fetch(
|
return await fetch(
|
||||||
`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_USER_ID}/ai/run/@cf/meta/llama-3-8b-instruct`,
|
`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) => {
|
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",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
sandboxId,
|
sandboxId,
|
||||||
userId
|
userId,
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
const data = await res.json()
|
const data = await res.json();
|
||||||
|
|
||||||
return data
|
return data;
|
||||||
}
|
};
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
import { type ClassValue, clsx } from "clsx"
|
import { type ClassValue, clsx } from "clsx";
|
||||||
// import { toast } from "sonner"
|
// import { toast } from "sonner"
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from "tailwind-merge";
|
||||||
import { Sandbox, TFile, TFolder } from "./types"
|
import { Sandbox, TFile, TFolder } from "./types";
|
||||||
|
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processFileType(file: string) {
|
export function processFileType(file: string) {
|
||||||
const ending = file.split(".").pop()
|
const ending = file.split(".").pop();
|
||||||
|
|
||||||
if (ending === "ts" || ending === "tsx") return "typescript"
|
if (ending === "ts" || ending === "tsx") return "typescript";
|
||||||
if (ending === "js" || ending === "jsx") return "javascript"
|
if (ending === "js" || ending === "jsx") return "javascript";
|
||||||
|
|
||||||
if (ending) return ending
|
if (ending) return ending;
|
||||||
return "plaintext"
|
return "plaintext";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateName(
|
export function validateName(
|
||||||
@ -24,7 +23,7 @@ export function validateName(
|
|||||||
type: "file" | "folder"
|
type: "file" | "folder"
|
||||||
) {
|
) {
|
||||||
if (newName === oldName || newName.length === 0) {
|
if (newName === oldName || newName.length === 0) {
|
||||||
return { status: false, message: "" }
|
return { status: false, message: "" };
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
newName.includes("/") ||
|
newName.includes("/") ||
|
||||||
@ -33,12 +32,17 @@ export function validateName(
|
|||||||
(type === "file" && !newName.includes(".")) ||
|
(type === "file" && !newName.includes(".")) ||
|
||||||
(type === "folder" && 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<React.SetStateAction<(TFolder | TFile)[]>>, sandboxData: Sandbox) {
|
export function addNew(
|
||||||
|
name: string,
|
||||||
|
type: "file" | "folder",
|
||||||
|
setFiles: React.Dispatch<React.SetStateAction<(TFolder | TFile)[]>>,
|
||||||
|
sandboxData: Sandbox
|
||||||
|
) {
|
||||||
if (type === "file") {
|
if (type === "file") {
|
||||||
setFiles((prev) => [
|
setFiles((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
@ -46,34 +50,44 @@ export function addNew(name: string, type: "file" | "folder", setFiles: React.Di
|
|||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
console.log("adding folder");
|
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 {
|
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",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
sandboxId,
|
sandboxId,
|
||||||
userId
|
userId,
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
console.error("Failed to start server", res)
|
console.error("Failed to start server", res);
|
||||||
callback(false)
|
callback(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(true)
|
callback(true);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to start server", error)
|
console.error("Failed to start server", error);
|
||||||
|
|
||||||
callback(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
callback(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user