transfer to ecs
This commit is contained in:
parent
509669ea30
commit
80547e9ae1
@ -1,20 +0,0 @@
|
||||
# This file specifies files that are *not* uploaded to Google Cloud
|
||||
# using gcloud. It follows the same syntax as .gitignore, with the addition of
|
||||
# "#!include" directives (which insert the entries of the given .gitignore-style
|
||||
# file at that point).
|
||||
#
|
||||
# For more information, run:
|
||||
# $ gcloud topic gcloudignore
|
||||
#
|
||||
.gcloudignore
|
||||
# If you would like to upload your .git directory, .gitignore file or files
|
||||
# from your .gitignore file, remove the corresponding line
|
||||
# below:
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Node.js dependencies:
|
||||
node_modules/
|
||||
.env
|
||||
|
||||
ingressController.yaml
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"watch": ["src"],
|
||||
"ext": "ts",
|
||||
"exec": "concurrently \"npx tsc --watch\" \"ts-node src/index.ts\""
|
||||
}
|
2528
backend/orchestrator/package-lock.json
generated
2528
backend/orchestrator/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
{
|
||||
"name": "orchestrator",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"build": "npm i && npx tsc",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "nodemon src/index.ts"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@kubernetes/client-node": "^0.21.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
"yaml": "^2.4.2",
|
||||
"zod": "^3.23.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4.5",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.12.8",
|
||||
"nodemon": "^3.1.0",
|
||||
"ts-node": "^10.9.2"
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: <SANDBOX>
|
||||
labels:
|
||||
app: <SANDBOX>
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: <SANDBOX>
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: <SANDBOX>
|
||||
spec:
|
||||
volumes:
|
||||
- name: projects-volume
|
||||
emptyDir: {}
|
||||
containers:
|
||||
- name: sandbox
|
||||
image: ishaan1013/sandbox:latest
|
||||
ports:
|
||||
- containerPort: 4000
|
||||
- containerPort: 3000
|
||||
volumeMounts:
|
||||
- name: projects-volume
|
||||
mountPath: /projects
|
||||
resources:
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: "1Gi"
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: "1Gi"
|
||||
env:
|
||||
- name: CF_AI_KEY
|
||||
value: <CF_AI_KEY>
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: <SANDBOX>
|
||||
spec:
|
||||
selector:
|
||||
app: <SANDBOX>
|
||||
ports:
|
||||
- protocol: TCP
|
||||
name: ws
|
||||
port: 4000
|
||||
targetPort: 4000
|
||||
- protocol: TCP
|
||||
name: user
|
||||
port: 3000
|
||||
targetPort: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: <SANDBOX>
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: <SANDBOX>.ws.ishaand.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: <SANDBOX>
|
||||
port:
|
||||
number: 4000
|
||||
- host: <SANDBOX>.sandbox.ishaand.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: <SANDBOX>
|
||||
port:
|
||||
number: 3000
|
@ -1,221 +0,0 @@
|
||||
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 {
|
||||
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();
|
||||
|
||||
// const corsOptions = {
|
||||
// origin: ['http://localhost:3000', 'https://s.ishaand.com', 'http://localhost:4000', /\.ws\.ishaand\.com$/],
|
||||
// }
|
||||
// app.use(cors(corsOptions))
|
||||
|
||||
app.use(cors());
|
||||
|
||||
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 readAndParseKubeYaml = (
|
||||
filePath: string,
|
||||
sandboxId: string
|
||||
): Array<any> => {
|
||||
const fileContent = fs.readFileSync(filePath, "utf8");
|
||||
const docs = yaml.parseAllDocuments(fileContent).map((doc) => {
|
||||
let docString = doc.toString();
|
||||
|
||||
const regex = new RegExp(`<SANDBOX>`, "g");
|
||||
docString = docString.replace(regex, sandboxId);
|
||||
|
||||
if (!process.env.CF_AI_KEY) {
|
||||
throw new Error("CF_AI_KEY is not defined");
|
||||
}
|
||||
|
||||
const regexEnv = new RegExp(`<CF_AI_KEY>`, "g");
|
||||
docString = docString.replace(regexEnv, process.env.CF_AI_KEY);
|
||||
|
||||
return yaml.parse(docString);
|
||||
});
|
||||
return docs;
|
||||
};
|
||||
|
||||
const dataSchema = z.object({
|
||||
userId: z.string(),
|
||||
sandboxId: z.string(),
|
||||
});
|
||||
|
||||
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.",
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/start", async (req, res) => {
|
||||
const { sandboxId } = dataSchema.parse(req.body);
|
||||
|
||||
try {
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
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);
|
||||
console.log(`Created ${kind.toLowerCase()}`, name);
|
||||
} else {
|
||||
console.log(`${kind} ${name} already exists.`);
|
||||
}
|
||||
};
|
||||
|
||||
const promises = kubeManifests.map(async (manifest) => {
|
||||
const {
|
||||
kind,
|
||||
metadata: { name },
|
||||
} = manifest;
|
||||
|
||||
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);
|
||||
default:
|
||||
console.error("Unsupported kind:", manifest.kind);
|
||||
return Promise.reject("Unsupported kind: " + manifest.kind);
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
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);
|
||||
|
||||
if (body.code === 409) {
|
||||
return res.status(200).send({ message: "Resource already exists." });
|
||||
}
|
||||
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);
|
||||
|
||||
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." });
|
||||
} catch (error) {
|
||||
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}`);
|
||||
});
|
@ -1,109 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./dist",
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
@ -21,5 +21,6 @@ RUN mkdir projects && chown -R myuser:myuser projects
|
||||
USER myuser
|
||||
|
||||
EXPOSE 3000
|
||||
EXPOSE 4000
|
||||
|
||||
CMD [ "node", "dist/index.js" ]
|
1157
backend/server/package-lock.json
generated
1157
backend/server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-ecs": "^3.577.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
renameFile,
|
||||
saveFile,
|
||||
stopServer,
|
||||
testDescribe,
|
||||
} from "./utils";
|
||||
import { IDisposable, IPty, spawn } from "node-pty";
|
||||
import {
|
||||
@ -115,6 +116,10 @@ io.on("connection", async (socket) => {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("describing service:");
|
||||
const describeService = await testDescribe();
|
||||
console.log(describeService);
|
||||
|
||||
const sandboxFiles = await getSandboxFiles(data.sandboxId);
|
||||
sandboxFiles.fileData.forEach((file) => {
|
||||
const filePath = path.join(dirName, file.id);
|
||||
@ -290,9 +295,9 @@ io.on("connection", async (socket) => {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("renameFolder", async (folderId: string, newName: string) => {
|
||||
// todo
|
||||
});
|
||||
// todo
|
||||
// socket.on("renameFolder", async (folderId: string, newName: string) => {
|
||||
// });
|
||||
|
||||
socket.on("deleteFolder", async (folderId: string, callback) => {
|
||||
const files = await getFolder(folderId);
|
||||
@ -329,7 +334,6 @@ io.on("connection", async (socket) => {
|
||||
});
|
||||
|
||||
const onData = pty.onData((data) => {
|
||||
// console.log("terminalResponse", id, data)
|
||||
io.emit("terminalResponse", {
|
||||
id,
|
||||
data,
|
||||
@ -430,7 +434,6 @@ io.on("connection", async (socket) => {
|
||||
socket.on("disconnect", async () => {
|
||||
console.log("disconnected", data.userId, data.sandboxId);
|
||||
if (data.isOwner) {
|
||||
// console.log("deleting all terminals")
|
||||
Object.entries(terminals).forEach((t) => {
|
||||
const { terminal, onData, onExit } = t[1];
|
||||
onData.dispose();
|
||||
@ -453,9 +456,8 @@ io.on("connection", async (socket) => {
|
||||
inactivityTimeout = setTimeout(() => {
|
||||
io.fetchSockets().then(async (sockets) => {
|
||||
if (sockets.length === 0) {
|
||||
// close server
|
||||
console.log("Closing server due to inactivity.");
|
||||
const res = await stopServer(data.sandboxId, data.userId);
|
||||
// const res = await stopServer(data.sandboxId, data.userId);
|
||||
}
|
||||
});
|
||||
}, 20000);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import e from "cors";
|
||||
import * as dotenv from "dotenv";
|
||||
import {
|
||||
R2FileBody,
|
||||
R2Files,
|
||||
@ -9,6 +9,33 @@ import {
|
||||
User,
|
||||
} from "./types";
|
||||
|
||||
import {
|
||||
DescribeServicesCommand,
|
||||
ECSClient,
|
||||
StartTaskCommand,
|
||||
StopTaskCommand,
|
||||
} from "@aws-sdk/client-ecs";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const client = new ECSClient({
|
||||
region: "us-east-1",
|
||||
credentials: {
|
||||
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
||||
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
|
||||
},
|
||||
});
|
||||
|
||||
export const testDescribe = async () => {
|
||||
const command = new DescribeServicesCommand({
|
||||
cluster: "Sandbox",
|
||||
services: ["Sandbox"],
|
||||
});
|
||||
const response = await client.send(command);
|
||||
console.log("describing: ", response);
|
||||
return response;
|
||||
};
|
||||
|
||||
export const getSandboxFiles = async (id: string) => {
|
||||
const res = await fetch(
|
||||
`https://storage.ishaan1013.workers.dev/api?sandboxId=${id}`
|
||||
@ -151,18 +178,16 @@ export const getProjectSize = async (id: string) => {
|
||||
return (await res.json()).size;
|
||||
};
|
||||
|
||||
export const stopServer = async (sandboxId: string, userId: string) => {
|
||||
const res = await fetch("http://localhost:4001/stop", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
sandboxId,
|
||||
userId,
|
||||
}),
|
||||
export const stopServer = async (task: string) => {
|
||||
const command = new StopTaskCommand({
|
||||
cluster: "arn:aws:ecs:us-east-1:767398085538:service/Sandbox/Sandbox",
|
||||
task,
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
return data;
|
||||
try {
|
||||
const response = await client.send(command);
|
||||
console.log("Stopped server:", response);
|
||||
} catch (error) {
|
||||
console.error("Error stopping server:", error);
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user