Compare commits

..

6 Commits

Author SHA1 Message Date
08d562ee54 chore: remove unused variable reactDefinitionFile 2024-07-17 10:49:58 -04:00
db1410f587 fix: remove editorRef from useEffect 2024-07-17 10:46:34 -04:00
7a80734c25 fix: remove extra state variables from useEffect 2024-07-17 10:46:29 -04:00
0a21cb2637 fix: store rooms in map 2024-07-17 10:46:21 -04:00
2fbabbd403 fix: handle file save bug (#36) 2024-06-27 23:43:18 -07:00
9f0b6a8fdc Implement secure cloud sandboxes with E2B (#35)
* chore: rename utils.ts to fileoperations.ts

* feat: replace node-pty with E2B sandboxes

* added debounced function in the editor

* fix: move socket connection to useRef

* fix: wait until terminals are killed to close the container

* fix: ensure container remains open until all owner connections are closed

* fix: sync files to container instead of local file system

* fix: set project file permissions so that they belong to the terminal user

* fix: use the container URL for the preview panel

* fix: count only the current user's sandboxes towards the limit

* fix: remove hardcoded reference to localhost

* fix: add error handling to the backend

* docs: add information about E2B

---------

Co-authored-by: Akhilesh Rangani <akhileshrangani4@gmail.com>
2024-06-27 23:39:03 -07:00
5 changed files with 7 additions and 14 deletions

View File

@ -29,7 +29,9 @@ npm run dev
### Backend
The backend consists of a primary Express and Socket.io server, and 3 Cloudflare Workers microservices for the D1 database, R2 storage, and Workers AI. The D1 database also contains a [service binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/) to the R2 storage worker.
The backend consists of a primary Express and Socket.io server, and 3 Cloudflare Workers microservices for the D1 database, R2 storage, and Workers AI. The D1 database also contains a [service binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/) to the R2 storage worker. Each open sandbox instantiates a secure Linux sandboxes on E2B, which is used for the terminal and live preview.
You will need to make an account on [E2B](https://e2b.dev/) to get an API key.
#### Socket.io server
@ -181,3 +183,4 @@ It should be in the form `category(scope or module): message` in your commit mes
- [Express](https://expressjs.com/)
- [Socket.io](https://socket.io/)
- [Drizzle ORM](https://orm.drizzle.team/)
- [E2B](https://e2b.dev/)

View File

@ -5,3 +5,4 @@ PORT=4000
WORKERS_KEY=
DATABASE_WORKER_URL=
STORAGE_WORKER_URL=
E2B_API_KEY=

View File

@ -192,6 +192,8 @@ io.on("connection", async (socket) => {
// todo: send diffs + debounce for efficiency
socket.on("saveFile", async (fileId: string, body: string) => {
if (!fileId) return; // handles saving when no file is open
try {
if (Buffer.byteLength(body, "utf-8") > MAX_BODY_SIZE) {
socket.emit(

View File

@ -63,14 +63,6 @@ const CodeEditor = dynamic(() => import("@/components/editor"), {
loading: () => <Loading />,
})
function getReactDefinitionFile() {
const reactDefinitionFile = fs.readFileSync(
"node_modules/@types/react/index.d.ts",
"utf8"
)
return reactDefinitionFile
}
export default async function CodePage({ params }: { params: { id: string } }) {
const user = await currentUser()
const sandboxId = params.id
@ -94,8 +86,6 @@ export default async function CodePage({ params }: { params: { id: string } }) {
return notFound()
}
const reactDefinitionFile = getReactDefinitionFile()
return (
<div className="overflow-hidden overscroll-none w-screen flex flex-col h-screen bg-background">
<Room id={sandboxId}>
@ -104,7 +94,6 @@ export default async function CodePage({ params }: { params: { id: string } }) {
<CodeEditor
userData={userData}
sandboxData={sandboxData}
reactDefinitionFile={reactDefinitionFile}
/>
</div>
</Room>

View File

@ -35,11 +35,9 @@ import { ImperativePanelHandle } from "react-resizable-panels"
export default function CodeEditor({
userData,
sandboxData,
reactDefinitionFile,
}: {
userData: User
sandboxData: Sandbox
reactDefinitionFile: string
}) {
const socketRef = useRef<Socket | null>(null);