From 0fe652d8733fe183957d45ba62896322650cf7c8 Mon Sep 17 00:00:00 2001 From: James Murdza Date: Thu, 24 Oct 2024 20:00:50 -0600 Subject: [PATCH] refactor: package websocket event arguments as objects --- backend/server/src/SocketHandlers.ts | 34 ++-- backend/server/src/index.ts | 71 ++++---- frontend/components/editor/generate.tsx | 10 +- frontend/components/editor/index.tsx | 157 ++++++++---------- frontend/components/editor/sidebar/index.tsx | 6 +- frontend/components/editor/sidebar/new.tsx | 4 +- .../components/editor/terminals/terminal.tsx | 4 +- frontend/context/TerminalContext.tsx | 4 +- frontend/lib/terminal.ts | 10 +- tests/index.ts | 6 +- 10 files changed, 148 insertions(+), 158 deletions(-) diff --git a/backend/server/src/SocketHandlers.ts b/backend/server/src/SocketHandlers.ts index 43a60cc..a0d1f10 100644 --- a/backend/server/src/SocketHandlers.ts +++ b/backend/server/src/SocketHandlers.ts @@ -25,38 +25,38 @@ function extractPortNumber(inputString: string): number | null { } // Handle heartbeat from a socket connection -export function handleHeartbeat(data: any, context: HandlerContext) { +export function handleHeartbeat({ data }: { data: any }, context: HandlerContext) { context.sandboxManager.setTimeout(CONTAINER_TIMEOUT) } // Handle getting a file -export function handleGetFile(fileId: string, context: HandlerContext) { +export function handleGetFile({ fileId }: { fileId: string }, context: HandlerContext) { return context.fileManager.getFile(fileId) } // Handle getting a folder -export function handleGetFolder(folderId: string, context: HandlerContext) { +export function handleGetFolder({ folderId }: { folderId: string }, context: HandlerContext) { return context.fileManager.getFolder(folderId) } // Handle saving a file -export function handleSaveFile(fileId: string, body: string, context: HandlerContext) { +export function handleSaveFile({ fileId, body }: { fileId: string, body: string }, context: HandlerContext) { return context.fileManager.saveFile(fileId, body) } // Handle moving a file -export function handleMoveFile(fileId: string, folderId: string, context: HandlerContext) { +export function handleMoveFile({ fileId, folderId }: { fileId: string, folderId: string }, context: HandlerContext) { return context.fileManager.moveFile(fileId, folderId) } // Handle listing apps -export async function handleListApps(context: HandlerContext) { +export async function handleListApps({ }, context: HandlerContext) { if (!context.dokkuClient) throw Error("Failed to retrieve apps list: No Dokku client") return { success: true, apps: await context.dokkuClient.listApps() } } // Handle deploying code -export async function handleDeploy(sandboxId: string, context: HandlerContext) { +export async function handleDeploy({ sandboxId }: { sandboxId: string }, context: HandlerContext) { if (!context.gitClient) throw Error("Failed to retrieve apps list: No git client") const fixedFilePaths = context.fileManager.sandboxFiles.fileData.map((file) => ({ ...file, @@ -67,32 +67,32 @@ export async function handleDeploy(sandboxId: string, context: HandlerContext) { } // Handle creating a file -export function handleCreateFile(name: string, context: HandlerContext) { +export function handleCreateFile({ name }: { name: string }, context: HandlerContext) { return context.fileManager.createFile(name) } // Handle creating a folder -export function handleCreateFolder(name: string, context: HandlerContext) { +export function handleCreateFolder({ name }: { name: string }, context: HandlerContext) { return context.fileManager.createFolder(name) } // Handle renaming a file -export function handleRenameFile(fileId: string, newName: string, context: HandlerContext) { +export function handleRenameFile({ fileId, newName }: { fileId: string, newName: string }, context: HandlerContext) { return context.fileManager.renameFile(fileId, newName) } // Handle deleting a file -export function handleDeleteFile(fileId: string, context: HandlerContext) { +export function handleDeleteFile({ fileId }: { fileId: string }, context: HandlerContext) { return context.fileManager.deleteFile(fileId) } // Handle deleting a folder -export function handleDeleteFolder(folderId: string, context: HandlerContext) { +export function handleDeleteFolder({ folderId }: { folderId: string }, context: HandlerContext) { return context.fileManager.deleteFolder(folderId) } // Handle creating a terminal session -export async function handleCreateTerminal(id: string, socket: any, data: any, context: HandlerContext) { +export async function handleCreateTerminal({ id, socket, data }: { id: string, socket: any, data: any }, context: HandlerContext) { await context.lockManager.acquireLock(data.sandboxId, async () => { await context.terminalManager.createTerminal(id, (responseString: string) => { socket.emit("terminalResponse", { id, data: responseString }) @@ -108,21 +108,21 @@ export async function handleCreateTerminal(id: string, socket: any, data: any, c } // Handle resizing a terminal -export function handleResizeTerminal(dimensions: { cols: number; rows: number }, context: HandlerContext) { +export function handleResizeTerminal({ dimensions }: { dimensions: { cols: number; rows: number } }, context: HandlerContext) { context.terminalManager.resizeTerminal(dimensions) } // Handle sending data to a terminal -export function handleTerminalData(id: string, data: string, context: HandlerContext) { +export function handleTerminalData({ id, data }: { id: string, data: string }, context: HandlerContext) { return context.terminalManager.sendTerminalData(id, data) } // Handle closing a terminal -export function handleCloseTerminal(id: string, context: HandlerContext) { +export function handleCloseTerminal({ id }: { id: string }, context: HandlerContext) { return context.terminalManager.closeTerminal(id) } // Handle generating code -export function handleGenerateCode(userId: string, fileName: string, code: string, line: number, instructions: string, context: HandlerContext) { +export function handleGenerateCode({ userId, fileName, code, line, instructions }: { userId: string, fileName: string, code: string, line: number, instructions: string }, context: HandlerContext) { return context.aiWorker.generateCode(userId, fileName, code, line, instructions) } \ No newline at end of file diff --git a/backend/server/src/index.ts b/backend/server/src/index.ts index da288de..9d5aa67 100644 --- a/backend/server/src/index.ts +++ b/backend/server/src/index.ts @@ -181,160 +181,159 @@ io.on("connection", async (socket) => { } // Handle various socket events (heartbeat, file operations, terminal operations, etc.) - socket.on("heartbeat", async (callback) => { + socket.on("heartbeat", async (options, callback) => { try { - callback?.(handleHeartbeat(data, handlerContext)) + callback?.(handleHeartbeat(options, handlerContext)) } catch (e: any) { console.error("Error setting timeout:", e) socket.emit("error", `Error: set timeout. ${e.message ?? e}`) } }) - socket.on("getFile", async (fileId: string, callback) => { + socket.on("getFile", async (options, callback) => { try { - callback?.(await handleGetFile(fileId, handlerContext)) + callback?.(await handleGetFile(options, handlerContext)) } catch (e: any) { console.error("Error getting file:", e) socket.emit("error", `Error: get file. ${e.message ?? e}`) } }) - socket.on("getFolder", async (folderId: string, callback) => { + socket.on("getFolder", async (options, callback) => { try { - callback?.(await handleGetFolder(folderId, handlerContext)) + callback?.(await handleGetFolder(options, handlerContext)) } catch (e: any) { console.error("Error getting folder:", e) socket.emit("error", `Error: get folder. ${e.message ?? e}`) } }) - socket.on("saveFile", async (fileId: string, body: string, callback) => { + socket.on("saveFile", async (options, callback) => { try { await saveFileRL.consume(data.userId, 1) - callback?.(await handleSaveFile(fileId, body, handlerContext)) + callback?.(await handleSaveFile(options, handlerContext)) } catch (e: any) { console.error("Error saving file:", e) socket.emit("error", `Error: file saving. ${e.message ?? e}`) } }) - socket.on("moveFile", async (fileId: string, folderId: string, callback) => { + socket.on("moveFile", async (options, callback) => { try { - callback?.(await handleMoveFile(fileId, folderId, handlerContext)) + callback?.(await handleMoveFile(options, handlerContext)) } catch (e: any) { console.error("Error moving file:", e) socket.emit("error", `Error: file moving. ${e.message ?? e}`) } }) - socket.on("list", async (callback) => { + socket.on("list", async (options, callback) => { console.log("Retrieving apps list...") try { - callback?.(await handleListApps(handlerContext)) + callback?.(await handleListApps(options, handlerContext)) } catch (e: any) { console.error("Error retrieving apps list:", e) socket.emit("error", `Error: app list retrieval. ${e.message ?? e}`) } }) - socket.on("deploy", async (callback) => { + socket.on("deploy", async (options, callback) => { try { - console.log("Deploying project ${data.sandboxId}...") - callback?.(await handleDeploy(data.sandboxId, handlerContext)) + callback?.(await handleDeploy(options, handlerContext)) } catch (e: any) { console.error("Error deploying project:", e) socket.emit("error", `Error: project deployment. ${e.message ?? e}`) } }) - socket.on("createFile", async (name: string, callback) => { + socket.on("createFile", async (options, callback) => { try { await createFileRL.consume(data.userId, 1) - callback?.({ success: await handleCreateFile(name, handlerContext) }) + callback?.({ success: await handleCreateFile(options, handlerContext) }) } catch (e: any) { console.error("Error creating file:", e) socket.emit("error", `Error: file creation. ${e.message ?? e}`) } }) - socket.on("createFolder", async (name: string, callback) => { + socket.on("createFolder", async (options, callback) => { try { await createFolderRL.consume(data.userId, 1) - callback?.(await handleCreateFolder(name, handlerContext)) + callback?.(await handleCreateFolder(options, handlerContext)) } catch (e: any) { console.error("Error creating folder:", e) socket.emit("error", `Error: folder creation. ${e.message ?? e}`) } }) - socket.on("renameFile", async (fileId: string, newName: string, callback) => { + socket.on("renameFile", async (options, callback) => { try { await renameFileRL.consume(data.userId, 1) - callback?.(await handleRenameFile(fileId, newName, handlerContext)) + callback?.(await handleRenameFile(options, handlerContext)) } catch (e: any) { console.error("Error renaming file:", e) socket.emit("error", `Error: file renaming. ${e.message ?? e}`) } }) - socket.on("deleteFile", async (fileId: string, callback) => { + socket.on("deleteFile", async (options, callback) => { try { await deleteFileRL.consume(data.userId, 1) - callback?.(await handleDeleteFile(fileId, handlerContext)) + callback?.(await handleDeleteFile(options, handlerContext)) } catch (e: any) { console.error("Error deleting file:", e) socket.emit("error", `Error: file deletion. ${e.message ?? e}`) } }) - socket.on("deleteFolder", async (folderId: string, callback) => { + socket.on("deleteFolder", async (options, callback) => { try { - callback?.(await handleDeleteFolder(folderId, handlerContext)) + callback?.(await handleDeleteFolder(options, handlerContext)) } catch (e: any) { console.error("Error deleting folder:", e) socket.emit("error", `Error: folder deletion. ${e.message ?? e}`) } }) - socket.on("createTerminal", async (id: string, callback) => { + socket.on("createTerminal", async (options, callback) => { try { - callback?.(await handleCreateTerminal(id, socket, data, handlerContext)) + callback?.(await handleCreateTerminal(options, handlerContext)) } catch (e: any) { - console.error(`Error creating terminal ${id}:`, e) + console.error(`Error creating terminal ${options.id}:`, e) socket.emit("error", `Error: terminal creation. ${e.message ?? e}`) } }) - socket.on("resizeTerminal", (dimensions: { cols: number; rows: number }, callback) => { + socket.on("resizeTerminal", (options, callback) => { try { - callback?.(handleResizeTerminal(dimensions, handlerContext)) + callback?.(handleResizeTerminal(options, handlerContext)) } catch (e: any) { console.error("Error resizing terminal:", e) socket.emit("error", `Error: terminal resizing. ${e.message ?? e}`) } }) - socket.on("terminalData", async (id: string, data: string, callback) => { + socket.on("terminalData", async (options, callback) => { try { - callback?.(await handleTerminalData(id, data, handlerContext)) + callback?.(await handleTerminalData(options, handlerContext)) } catch (e: any) { console.error("Error writing to terminal:", e) socket.emit("error", `Error: writing to terminal. ${e.message ?? e}`) } }) - socket.on("closeTerminal", async (id: string, callback) => { + socket.on("closeTerminal", async (options, callback) => { try { - callback?.(await handleCloseTerminal(id, handlerContext)) + callback?.(await handleCloseTerminal(options, handlerContext)) } catch (e: any) { console.error("Error closing terminal:", e) socket.emit("error", `Error: closing terminal. ${e.message ?? e}`) } }) - socket.on("generateCode", async (fileName: string, code: string, line: number, instructions: string, callback) => { + socket.on("generateCode", async (options, callback) => { try { - callback?.(await handleGenerateCode(data.userId, fileName, code, line, instructions, handlerContext)) + callback?.(await handleGenerateCode(options, handlerContext)) } catch (e: any) { console.error("Error generating code:", e) socket.emit("error", `Error: code generation. ${e.message ?? e}`) diff --git a/frontend/components/editor/generate.tsx b/frontend/components/editor/generate.tsx index 9e4bd09..0b5ff39 100644 --- a/frontend/components/editor/generate.tsx +++ b/frontend/components/editor/generate.tsx @@ -68,10 +68,12 @@ export default function GenerateInput({ setCurrentPrompt(input) socket.emit( "generateCode", - data.fileName, - data.code, - data.line, - regenerate ? currentPrompt : input, + { + fileName: data.fileName, + code: data.code, + line: data.line, + instructions: regenerate ? currentPrompt : input + }, (res: { response: string; success: boolean }) => { console.log("Generated code", res.response, res.success) // if (!res.success) { diff --git a/frontend/components/editor/index.tsx b/frontend/components/editor/index.tsx index e20a6d0..5435b8d 100644 --- a/frontend/components/editor/index.tsx +++ b/frontend/components/editor/index.tsx @@ -107,7 +107,7 @@ export default function CodeEditor({ // Editor state const [editorLanguage, setEditorLanguage] = useState("plaintext") - console.log("editor language: ",editorLanguage) + console.log("editor language: ", editorLanguage) const [cursorLine, setCursorLine] = useState(0) const [editorRef, setEditorRef] = useState() @@ -207,7 +207,7 @@ export default function CodeEditor({ ) const fetchFileContent = (fileId: string): Promise => { return new Promise((resolve) => { - socket?.emit("getFile", fileId, (content: string) => { + socket?.emit("getFile", { fileId }, (content: string) => { resolve(content) }) }) @@ -532,7 +532,7 @@ export default function CodeEditor({ ) console.log(`Saving file...${activeFileId}`) console.log(`Saving file...${content}`) - socket?.emit("saveFile", activeFileId, content) + socket?.emit("saveFile", { fileId: activeFileId, body: content }) } }, Number(process.env.FILE_SAVE_DEBOUNCE_DELAY) || 1000), [socket, fileContents] @@ -649,7 +649,7 @@ export default function CodeEditor({ // Socket event listener effect useEffect(() => { - const onConnect = () => {} + const onConnect = () => { } const onDisconnect = () => { setTerminals([]) @@ -715,7 +715,7 @@ export default function CodeEditor({ // Debounced function to get file content const debouncedGetFile = (tabId: any, callback: any) => { - socket?.emit("getFile", tabId, callback) + socket?.emit("getFile", { fileId: tabId }, callback) } // 300ms debounce delay, adjust as needed const selectFile = (tab: TTab) => { @@ -777,8 +777,8 @@ export default function CodeEditor({ ? numTabs === 1 ? null : index < numTabs - 1 - ? tabs[index + 1].id - : tabs[index - 1].id + ? tabs[index + 1].id + : tabs[index - 1].id : activeFileId setTabs((prev) => prev.filter((t) => t.id !== id)) @@ -835,7 +835,7 @@ export default function CodeEditor({ return false } - socket?.emit("renameFile", id, newName) + socket?.emit("renameFile", { fileId: id, newName }) setTabs((prev) => prev.map((tab) => (tab.id === id ? { ...tab, name: newName } : tab)) ) @@ -844,7 +844,7 @@ export default function CodeEditor({ } const handleDeleteFile = (file: TFile) => { - socket?.emit("deleteFile", file.id, (response: (TFolder | TFile)[]) => { + socket?.emit("deleteFile", { fileId: file.id }, (response: (TFolder | TFile)[]) => { setFiles(response) }) closeTab(file.id) @@ -854,11 +854,11 @@ export default function CodeEditor({ setDeletingFolderId(folder.id) console.log("deleting folder", folder.id) - socket?.emit("getFolder", folder.id, (response: string[]) => + socket?.emit("getFolder", { folderId: folder.id }, (response: string[]) => closeTabs(response) ) - socket?.emit("deleteFolder", folder.id, (response: (TFolder | TFile)[]) => { + socket?.emit("deleteFolder", { folderId: folder.id }, (response: (TFolder | TFile)[]) => { setFiles(response) setDeletingFolderId("") }) @@ -902,7 +902,7 @@ export default function CodeEditor({ {}} + setOpen={() => { }} /> @@ -944,8 +944,8 @@ export default function CodeEditor({ code: (isSelected && editorRef?.getSelection() ? editorRef - ?.getModel() - ?.getValueInRange(editorRef?.getSelection()!) + ?.getModel() + ?.getValueInRange(editorRef?.getSelection()!) : editorRef?.getValue()) ?? "", line: generate.line, }} @@ -1075,62 +1075,62 @@ export default function CodeEditor({ ) : // Note clerk.loaded is required here due to a bug: https://github.com/clerk/javascript/issues/1643 - clerk.loaded ? ( - <> - {provider && userInfo ? ( - - ) : null} - { - // If the new content is different from the cached content, update it - if (value !== fileContents[activeFileId]) { - setActiveFileContent(value ?? "") // Update the active file content - // Mark the file as unsaved by setting 'saved' to false - setTabs((prev) => - prev.map((tab) => - tab.id === activeFileId - ? { ...tab, saved: false } - : tab + clerk.loaded ? ( + <> + {provider && userInfo ? ( + + ) : null} + { + // If the new content is different from the cached content, update it + if (value !== fileContents[activeFileId]) { + setActiveFileContent(value ?? "") // Update the active file content + // Mark the file as unsaved by setting 'saved' to false + setTabs((prev) => + prev.map((tab) => + tab.id === activeFileId + ? { ...tab, saved: false } + : tab + ) ) - ) - } else { - // If the content matches the cached content, mark the file as saved - setTabs((prev) => - prev.map((tab) => - tab.id === activeFileId - ? { ...tab, saved: true } - : tab + } else { + // If the content matches the cached content, mark the file as saved + setTabs((prev) => + prev.map((tab) => + tab.id === activeFileId + ? { ...tab, saved: true } + : tab + ) ) - ) - } - }} - options={{ - tabSize: 2, - minimap: { - enabled: false, - }, - padding: { - bottom: 4, - top: 4, - }, - scrollBeyondLastLine: false, - fixedOverflowWidgets: true, - fontFamily: "var(--font-geist-mono)", - }} - theme={theme === "light" ? "vs" : "vs-dark"} - value={activeFileContent} - /> - - ) : ( -
- - Waiting for Clerk to load... -
- )} + } + }} + options={{ + tabSize: 2, + minimap: { + enabled: false, + }, + padding: { + bottom: 4, + top: 4, + }, + scrollBeyondLastLine: false, + fixedOverflowWidgets: true, + fontFamily: "var(--font-geist-mono)", + }} + theme={theme === "light" ? "vs" : "vs-dark"} + value={activeFileContent} + /> + + ) : ( +
+ + Waiting for Clerk to load... +
+ )} @@ -1140,10 +1140,10 @@ export default function CodeEditor({ isAIChatOpen && isHorizontalLayout ? "horizontal" : isAIChatOpen - ? "vertical" - : isHorizontalLayout - ? "horizontal" - : "vertical" + ? "vertical" + : isHorizontalLayout + ? "horizontal" + : "vertical" } > { setFiles(response) setMovingId("") diff --git a/frontend/components/editor/sidebar/new.tsx b/frontend/components/editor/sidebar/new.tsx index 7fec344..ca7dbc9 100644 --- a/frontend/components/editor/sidebar/new.tsx +++ b/frontend/components/editor/sidebar/new.tsx @@ -27,7 +27,7 @@ export default function New({ if (type === "file") { socket.emit( "createFile", - name, + { name }, ({ success }: { success: boolean }) => { if (success) { addNew(name, type) @@ -35,7 +35,7 @@ export default function New({ } ) } else { - socket.emit("createFolder", name, () => { + socket.emit("createFolder", { name }, () => { addNew(name, type) }) } diff --git a/frontend/components/editor/terminals/terminal.tsx b/frontend/components/editor/terminals/terminal.tsx index 4790a44..19b3980 100644 --- a/frontend/components/editor/terminals/terminal.tsx +++ b/frontend/components/editor/terminals/terminal.tsx @@ -65,12 +65,12 @@ export default function EditorTerminal({ } const disposableOnData = term.onData((data) => { - socket.emit("terminalData", id, data) + socket.emit("terminalData", { id, data }) }) const disposableOnResize = term.onResize((dimensions) => { fitAddonRef.current?.fit() - socket.emit("terminalResize", dimensions) + socket.emit("terminalResize", { dimensions }) }) const resizeObserver = new ResizeObserver( debounce((entries) => { diff --git a/frontend/context/TerminalContext.tsx b/frontend/context/TerminalContext.tsx index a7f131a..5af74a8 100644 --- a/frontend/context/TerminalContext.tsx +++ b/frontend/context/TerminalContext.tsx @@ -63,7 +63,7 @@ export const TerminalProvider: React.FC<{ children: React.ReactNode }> = ({ terminals, setTerminals, setActiveTerminalId, - setClosingTerminal: () => {}, + setClosingTerminal: () => { }, socket, activeTerminalId, }) @@ -73,7 +73,7 @@ export const TerminalProvider: React.FC<{ children: React.ReactNode }> = ({ const deploy = (callback: () => void) => { if (!socket) console.error("Couldn't deploy: No socket") console.log("Deploying...") - socket?.emit("deploy", () => { + socket?.emit("deploy", {}, () => { callback() }) } diff --git a/frontend/lib/terminal.ts b/frontend/lib/terminal.ts index a91db3c..1d0edbc 100644 --- a/frontend/lib/terminal.ts +++ b/frontend/lib/terminal.ts @@ -32,9 +32,9 @@ export const createTerminal = ({ setActiveTerminalId(id) setTimeout(() => { - socket.emit("createTerminal", id, () => { + socket.emit("createTerminal", { id }, () => { setCreatingTerminal(false) - if (command) socket.emit("terminalData", id, command + "\n") + if (command) socket.emit("terminalData", { id, data: command + "\n" }) }) }, 1000) } @@ -75,7 +75,7 @@ export const closeTerminal = ({ setClosingTerminal(term.id) - socket.emit("closeTerminal", term.id, () => { + socket.emit("closeTerminal", { id: term.id }, () => { setClosingTerminal("") const nextId = @@ -83,8 +83,8 @@ export const closeTerminal = ({ ? numTerminals === 1 ? null : index < numTerminals - 1 - ? terminals[index + 1].id - : terminals[index - 1].id + ? terminals[index + 1].id + : terminals[index - 1].id : activeTerminalId setTerminals((prev) => prev.filter((t) => t.id !== term.id)) diff --git a/tests/index.ts b/tests/index.ts index a36868c..951eefe 100644 --- a/tests/index.ts +++ b/tests/index.ts @@ -1,6 +1,6 @@ // Import necessary modules -import { io, Socket } from "socket.io-client"; import dotenv from "dotenv"; +import { io, Socket } from "socket.io-client"; dotenv.config(); @@ -21,7 +21,7 @@ socketRef.on("connect", async () => { console.log("Connected to the server"); await new Promise((resolve) => setTimeout(resolve, 1000)); - socketRef.emit("list", (response: CallbackResponse) => { + socketRef.emit("list", {}, (response: CallbackResponse) => { if (response.success) { console.log("List of apps:", response.apps); } else { @@ -29,7 +29,7 @@ socketRef.on("connect", async () => { } }); - socketRef.emit("deploy", (response: CallbackResponse) => { + socketRef.emit("deploy", {}, (response: CallbackResponse) => { if (response.success) { console.log("It worked!"); } else {