start terminal ui + logic

This commit is contained in:
Ishaan Dey
2024-04-28 20:06:47 -04:00
parent 9726e7c249
commit ec900d3d77
12 changed files with 322 additions and 56 deletions

View File

@ -18,6 +18,7 @@ const http_1 = require("http");
const socket_io_1 = require("socket.io");
const zod_1 = require("zod");
const utils_1 = require("./utils");
const terminal_1 = require("./terminal");
dotenv_1.default.config();
const app = (0, express_1.default)();
const port = process.env.PORT || 4000;
@ -28,6 +29,7 @@ const io = new socket_io_1.Server(httpServer, {
origin: "*",
},
});
const terminals = {};
const handshakeSchema = zod_1.z.object({
userId: zod_1.z.string(),
sandboxId: zod_1.z.string(),
@ -70,6 +72,7 @@ io.on("connection", (socket) => __awaiter(void 0, void 0, void 0, function* () {
const file = sandboxFiles.fileData.find((f) => f.id === fileId);
if (!file)
return;
console.log("get file " + file.id + ": ", file.data.slice(0, 10) + "...");
callback(file.data);
});
// todo: send diffs + debounce for efficiency
@ -88,6 +91,21 @@ io.on("connection", (socket) => __awaiter(void 0, void 0, void 0, function* () {
file.id = newName;
yield (0, utils_1.renameFile)(fileId, newName, file.data);
}));
socket.on("createTerminal", ({ id }) => {
console.log("creating terminal (" + id + ")");
terminals[id] = new terminal_1.Pty(socket, id);
});
socket.on("terminalData", ({ id, data }) => {
console.log(`Received data for terminal ${id}: ${data}`);
if (!terminals[id]) {
console.log("terminal not found");
console.log("terminals", terminals);
return;
}
console.log(`Writing to terminal ${id}`);
terminals[id].write(data);
});
socket.on("disconnect", () => { });
}));
httpServer.listen(port, () => {
console.log(`Server running on port ${port}`);

35
backend/server/dist/terminal.js vendored Normal file
View File

@ -0,0 +1,35 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Pty = void 0;
const node_pty_1 = require("node-pty");
const os_1 = __importDefault(require("os"));
class Pty {
constructor(socket, id) {
this.socket = socket;
this.shell = os_1.default.platform() === "win32" ? "cmd.exe" : "bash";
this.ptyProcess = (0, node_pty_1.spawn)(this.shell, [], {
name: "xterm",
cols: 100,
cwd: `/temp`,
// env: process.env as { [key: string]: string },
});
this.ptyProcess.onData((data) => {
console.log("onData", data);
this.send(data);
});
// this.write("hello world")
}
write(data) {
console.log("writing data", data);
this.ptyProcess.write(data);
}
send(data) {
this.socket.emit("terminalResponse", {
data: Buffer.from(data, "utf-8"),
});
}
}
exports.Pty = Pty;

View File

@ -12,6 +12,7 @@
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"node-pty": "^1.0.0",
"socket.io": "^4.7.5",
"zod": "^3.22.4"
},
@ -977,6 +978,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/nan": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz",
"integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw=="
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@ -985,6 +991,15 @@
"node": ">= 0.6"
}
},
"node_modules/node-pty": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.0.0.tgz",
"integrity": "sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==",
"hasInstallScript": true,
"dependencies": {
"nan": "^2.17.0"
}
},
"node_modules/nodemon": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz",

View File

@ -14,6 +14,7 @@
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"node-pty": "^1.0.0",
"socket.io": "^4.7.5",
"zod": "^3.22.4"
},

View File

@ -6,6 +6,7 @@ import { Server } from "socket.io"
import { z } from "zod"
import { User } from "./types"
import { getSandboxFiles, renameFile, saveFile } from "./utils"
import { Pty } from "./terminal"
dotenv.config()
@ -19,6 +20,8 @@ const io = new Server(httpServer, {
},
})
const terminals: { [id: string]: Pty } = {}
const handshakeSchema = z.object({
userId: z.string(),
sandboxId: z.string(),
@ -76,6 +79,7 @@ io.on("connection", async (socket) => {
const file = sandboxFiles.fileData.find((f) => f.id === fileId)
if (!file) return
console.log("get file " + file.id + ": ", file.data.slice(0, 10) + "...")
callback(file.data)
})
@ -96,6 +100,26 @@ io.on("connection", async (socket) => {
await renameFile(fileId, newName, file.data)
})
socket.on("createTerminal", ({ id }: { id: string }) => {
console.log("creating terminal (" + id + ")")
terminals[id] = new Pty(socket, id)
})
socket.on("terminalData", ({ id, data }: { id: string; data: string }) => {
console.log(`Received data for terminal ${id}: ${data}`)
if (!terminals[id]) {
console.log("terminal not found")
console.log("terminals", terminals)
return
}
console.log(`Writing to terminal ${id}`)
terminals[id].write(data)
})
socket.on("disconnect", () => {})
})
httpServer.listen(port, () => {

View File

@ -0,0 +1,49 @@
import { spawn, IPty } from "node-pty"
import { Socket } from "socket.io"
import os from "os"
export class Pty {
socket: Socket
ptyProcess: IPty
shell: string
constructor(socket: Socket, id: string) {
this.socket = socket
this.shell = os.platform() === "win32" ? "cmd.exe" : "bash"
this.ptyProcess = spawn(this.shell, [], {
name: "xterm",
cols: 100,
cwd: `/temp`,
// env: process.env as { [key: string]: string },
})
this.ptyProcess.onData((data) => {
console.log("onData", data)
this.send(data)
})
// this.write("hello world")
}
write(data: string) {
console.log("writing data", data)
this.ptyProcess.write(data)
}
send(data: string) {
this.socket.emit("terminalResponse", {
data: Buffer.from(data, "utf-8"),
})
}
// kill() {
// console.log("killing terminal")
// if (os.platform() !== "win32") {
// this.ptyProcess.kill()
// return
// }
// }
}