From b348f1d51976965acc6ae7c854e0a6ba39298378 Mon Sep 17 00:00:00 2001 From: Ishaan Dey Date: Fri, 26 Apr 2024 22:34:56 -0400 Subject: [PATCH] client ws connection --- frontend/app/(app)/code/[id]/page.tsx | 59 +---------- frontend/components/editor/index.tsx | 41 +++++++- frontend/components/editor/sidebar/index.tsx | 30 ++++-- frontend/package-lock.json | 101 +++++++++++++++++++ frontend/package.json | 1 + 5 files changed, 164 insertions(+), 68 deletions(-) diff --git a/frontend/app/(app)/code/[id]/page.tsx b/frontend/app/(app)/code/[id]/page.tsx index b22810f..d6a5442 100644 --- a/frontend/app/(app)/code/[id]/page.tsx +++ b/frontend/app/(app)/code/[id]/page.tsx @@ -1,9 +1,8 @@ import Navbar from "@/components/editor/navbar" -import { TFile, TFolder } from "@/components/editor/sidebar/types" -import { R2Files, User } from "@/lib/types" +import { User } from "@/lib/types" import { currentUser } from "@clerk/nextjs" import dynamic from "next/dynamic" -import { notFound, redirect } from "next/navigation" +import { redirect } from "next/navigation" const CodeEditor = dynamic(() => import("@/components/editor"), { ssr: false, @@ -15,57 +14,6 @@ const getUserData = async (id: string) => { return userData } -const getSandboxFiles = async (id: string) => { - const sandboxRes = await fetch( - `https://storage.ishaan1013.workers.dev/api?sandboxId=${id}` - ) - const sandboxData: R2Files = await sandboxRes.json() - - if (sandboxData.objects.length === 0) return notFound() - const paths = sandboxData.objects.map((obj) => obj.key) - return processFiles(paths, id) -} - -const processFiles = (paths: string[], id: string): (TFile | TFolder)[] => { - const root: TFolder = { id: "/", type: "folder", name: "/", children: [] } - - paths.forEach((path) => { - const allParts = path.split("/") - if (allParts[1] !== id) return notFound() - - 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) - - if (existing) { - if (!isFile) { - current = existing as TFolder - } - } else { - if (isFile) { - const file: TFile = { id: path, type: "file", name: part } - current.children.push(file) - } else { - const folder: TFolder = { - id: path, - type: "folder", - name: part, - children: [], - } - current.children.push(folder) - current = folder - } - } - } - }) - - return root.children -} - export default async function CodePage({ params }: { params: { id: string } }) { const user = await currentUser() const sandboxId = params.id @@ -75,13 +23,12 @@ export default async function CodePage({ params }: { params: { id: string } }) { } const userData = await getUserData(user.id) - const sandboxFiles = await getSandboxFiles(sandboxId) return (
- +
) diff --git a/frontend/components/editor/index.tsx b/frontend/components/editor/index.tsx index 8885e76..b070c3a 100644 --- a/frontend/components/editor/index.tsx +++ b/frontend/components/editor/index.tsx @@ -2,7 +2,7 @@ import Editor, { OnMount } from "@monaco-editor/react" import monaco from "monaco-editor" -import { useRef, useState } from "react" +import { useEffect, useRef, useState } from "react" // import theme from "./theme.json" import { @@ -21,13 +21,50 @@ import Sidebar from "./sidebar" import { useClerk } from "@clerk/nextjs" import { TFile, TFolder } from "./sidebar/types" -export default function CodeEditor({ files }: { files: (TFile | TFolder)[] }) { +import { io } from "socket.io-client" + +export default function CodeEditor({ + userId, + sandboxId, +}: { + userId: string + sandboxId: string +}) { // const editorRef = useRef(null) // const handleEditorMount: OnMount = (editor, monaco) => { // editorRef.current = editor // } + const [files, setFiles] = useState<(TFolder | TFile)[]>([]) + + const socket = io( + `http://localhost:4000?userId=${userId}&sandboxId=${sandboxId}` + ) + + // connection/disconnection effect + useEffect(() => { + socket.connect() + + return () => { + socket.disconnect() + } + }, []) + + // event listener effect + useEffect(() => { + function onLoadedEvent(files: (TFolder | TFile)[]) { + setFiles(files) + } + + socket.on("loaded", onLoadedEvent) + + return () => { + socket.off("loaded", onLoadedEvent) + } + }, []) + // use the dependency array! + const clerk = useClerk() const [tabs, setTabs] = useState([]) diff --git a/frontend/components/editor/sidebar/index.tsx b/frontend/components/editor/sidebar/index.tsx index 6e51fea..535a702 100644 --- a/frontend/components/editor/sidebar/index.tsx +++ b/frontend/components/editor/sidebar/index.tsx @@ -1,6 +1,6 @@ "use client" -import { FilePlus, FolderPlus, Search } from "lucide-react" +import { FilePlus, FolderPlus, Loader2, Search } from "lucide-react" import SidebarFile from "./file" import SidebarFolder from "./folder" import { TFile, TFolder } from "./types" @@ -34,15 +34,25 @@ export default function Sidebar({
- {files.map((child) => - child.type === "file" ? ( - - ) : ( - + {files.length === 0 ? ( +
+ +
+ ) : ( + files.map((child) => + child.type === "file" ? ( + + ) : ( + + ) ) )}
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 21b44ba..6632410 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -29,6 +29,7 @@ "react-dom": "^18", "react-hook-form": "^7.51.3", "react-resizable-panels": "^2.0.16", + "socket.io-client": "^4.7.5", "tailwind-merge": "^2.2.2", "tailwindcss-animate": "^1.0.7", "vscode-icons-js": "^11.6.1", @@ -1262,6 +1263,11 @@ "@babel/runtime": "^7.13.10" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, "node_modules/@swc/helpers": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", @@ -1796,6 +1802,22 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "devOptional": true }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", @@ -1852,6 +1874,26 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "node_modules/engine.io-client": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", @@ -2284,6 +2326,11 @@ "fast-plist": "^0.1.3" } }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -2939,6 +2986,32 @@ "node": ">=12" } }, + "node_modules/socket.io-client": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", + "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/source-map-js": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.1.0.tgz", @@ -3461,6 +3534,34 @@ "node": ">=8" } }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/yaml": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 6d88d4e..54e94b3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,6 +30,7 @@ "react-dom": "^18", "react-hook-form": "^7.51.3", "react-resizable-panels": "^2.0.16", + "socket.io-client": "^4.7.5", "tailwind-merge": "^2.2.2", "tailwindcss-animate": "^1.0.7", "vscode-icons-js": "^11.6.1",