client ws connection

This commit is contained in:
Ishaan Dey 2024-04-26 22:34:56 -04:00
parent 66b873454d
commit b348f1d519
5 changed files with 164 additions and 68 deletions

View File

@ -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 (
<div className="overflow-hidden overscroll-none w-screen flex flex-col h-screen bg-background">
<Navbar userData={userData} />
<div className="w-screen flex grow">
<CodeEditor files={sandboxFiles} />
<CodeEditor userId={user.id} sandboxId={sandboxId} />
</div>
</div>
)

View File

@ -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 | monaco.editor.IStandaloneCodeEditor>(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<TFile[]>([])

View File

@ -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({
</div>
</div>
<div className="w-full mt-1 flex flex-col">
{files.map((child) =>
child.type === "file" ? (
<SidebarFile key={child.id} data={child} selectFile={selectFile} />
) : (
<SidebarFolder
key={child.id}
data={child}
selectFile={selectFile}
/>
{files.length === 0 ? (
<div className="w-full flex justify-center">
<Loader2 className="w-4 h-4 animate-spin" />
</div>
) : (
files.map((child) =>
child.type === "file" ? (
<SidebarFile
key={child.id}
data={child}
selectFile={selectFile}
/>
) : (
<SidebarFolder
key={child.id}
data={child}
selectFile={selectFile}
/>
)
)
)}
</div>

View File

@ -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",

View File

@ -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",