This commit is contained in:
Ishaan Dey 2024-05-25 20:13:31 -07:00
parent 08a898a82a
commit 74bb83f3ed
8 changed files with 87 additions and 103 deletions

View File

@ -237,7 +237,9 @@ export default {
const res = await db.query.user.findFirst({ const res = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.id, id), where: (user, { eq }) => eq(user.id, id),
with: { with: {
sandbox: true, sandbox: {
orderBy: (sandbox, { desc }) => [desc(sandbox.createdAt)],
},
usersToSandboxes: true, usersToSandboxes: true,
}, },
}); });

View File

@ -16,13 +16,13 @@ COPY . .
RUN npm run build RUN npm run build
# Security: Create non-root user and assign ownership # Security: Create non-root user and assign ownership
RUN useradd -m sboxuser RUN useradd -m appuser
RUN mkdir projects && chown -R sboxuser:sboxuser projects RUN mkdir projects && chown -R appuser:appuser projects
USER sboxuser USER appuser
# user namespace mapping # todo user namespace mapping
EXPOSE 8000 EXPOSE 3000
EXPOSE 5173 EXPOSE 4000
CMD [ "node", "dist/index.js" ] CMD [ "node", "dist/index.js" ]

View File

@ -51,19 +51,21 @@ const terminals: {
const dirName = path.join(__dirname, ".."); const dirName = path.join(__dirname, "..");
const handshakeSchema = z.object({
userId: z.string(),
sandboxId: z.string(),
EIO: z.string(),
transport: z.string(),
});
io.use(async (socket, next) => { io.use(async (socket, next) => {
console.log("Middleware");
const handshakeSchema = z.object({
userId: z.string(),
sandboxId: z.string(),
EIO: z.string(),
transport: z.string(),
});
const q = socket.handshake.query; const q = socket.handshake.query;
const parseQuery = handshakeSchema.safeParse(q); const parseQuery = handshakeSchema.safeParse(q);
if (!parseQuery.success) { if (!parseQuery.success) {
("Invalid request."); console.log("Invalid request.");
next(new Error("Invalid request.")); next(new Error("Invalid request."));
return; return;
} }
@ -75,6 +77,7 @@ io.use(async (socket, next) => {
const dbUserJSON = (await dbUser.json()) as User; const dbUserJSON = (await dbUser.json()) as User;
if (!dbUserJSON) { if (!dbUserJSON) {
console.log("DB error.");
next(new Error("DB error.")); next(new Error("DB error."));
return; return;
} }
@ -85,6 +88,7 @@ io.use(async (socket, next) => {
); );
if (!sandbox && !sharedSandboxes) { if (!sandbox && !sharedSandboxes) {
console.log("Invalid credentials.");
next(new Error("Invalid credentials.")); next(new Error("Invalid credentials."));
return; return;
} }
@ -145,6 +149,7 @@ io.on("connection", async (socket) => {
// todo: send diffs + debounce for efficiency // todo: send diffs + debounce for efficiency
socket.on("saveFile", async (fileId: string, body: string) => { socket.on("saveFile", async (fileId: string, body: string) => {
console.log("save");
try { try {
await saveFileRL.consume(data.userId, 1); await saveFileRL.consume(data.userId, 1);
@ -470,5 +475,5 @@ io.on("connection", async (socket) => {
}); });
httpServer.listen(port, () => { httpServer.listen(port, () => {
console.log(`Server, running on port ${port}`); console.log(`Server 123, running on port ${port}`);
}); });

View File

@ -56,8 +56,9 @@ import react from '@vitejs/plugin-react'
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
server: { server: {
port: 8000, port: 3000,
}, host: "0.0.0.0",
}
}) })
`, `,
}, },
@ -87,10 +88,12 @@ export default defineConfig({
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-family: sans-serif;
} }
h1 { h1 {
color: #fff; color: #000;
margin: 0; margin: 0;
} }

View File

@ -90,10 +90,6 @@ export default function CodeEditor({
terminal: Terminal | null; terminal: Terminal | null;
}[] }[]
>([]); >([]);
const [activeTerminalId, setActiveTerminalId] = useState("");
const [creatingTerminal, setCreatingTerminal] = useState(false);
const [closingTerminal, setClosingTerminal] = useState("");
const activeTerminal = terminals.find((t) => t.id === activeTerminalId);
const isOwner = sandboxData.userId === userData.id; const isOwner = sandboxData.userId === userData.id;
const clerk = useClerk(); const clerk = useClerk();
@ -752,14 +748,7 @@ export default function CodeEditor({
<Terminals <Terminals
terminals={terminals} terminals={terminals}
setTerminals={setTerminals} setTerminals={setTerminals}
activeTerminalId={activeTerminalId}
setActiveTerminalId={setActiveTerminalId}
socket={socket} socket={socket}
activeTerminal={activeTerminal}
creatingTerminal={creatingTerminal}
setCreatingTerminal={setCreatingTerminal}
closingTerminal={closingTerminal}
setClosingTerminal={setClosingTerminal}
/> />
) : ( ) : (
<div className="w-full h-full flex items-center justify-center text-lg font-medium text-muted-foreground/50 select-none"> <div className="w-full h-full flex items-center justify-center text-lg font-medium text-muted-foreground/50 select-none">

View File

@ -34,55 +34,50 @@ export default function Editor({
return; return;
} }
// startServer(sandboxData.id).then((response) => { startServer(sandboxData.id).then((response) => {
// if (!response.success) { if (!response.success) {
// toast.error(response.message); toast.error(response.message);
// setDidFail(true); setDidFail(true);
// } else { } else {
// setIsServiceRunning(true); setIsServiceRunning(true);
// checkServiceStatus(sandboxData.id) checkServiceStatus(sandboxData.id)
// .then(() => { .then(() => {
// setIsDeploymentActive(true); setIsDeploymentActive(true);
// getTaskIp(sandboxData.id) getTaskIp(sandboxData.id)
// .then((ip) => { .then((ip) => {
// setTaskIp(ip); setTaskIp(ip);
// }) })
// .catch(() => { .catch(() => {
// setDidFail(true); setDidFail(true);
// toast.error("An error occurred while getting your server IP."); toast.error("An error occurred while getting your server IP.");
// }); });
// }) })
// .catch(() => { .catch(() => {
// toast.error("An error occurred while initializing your server."); toast.error("An error occurred while initializing your server.");
// setDidFail(true); setDidFail(true);
// }); });
// } }
// }); });
}, []); }, []);
// if (didFail) return <Loading didFail={didFail} />; if (didFail) return <Loading didFail={didFail} />;
// if (!isServiceRunning || !isDeploymentActive || !taskIp) if (!isServiceRunning || !isDeploymentActive || !taskIp)
// return ( return (
// <Loading <Loading
// text="Creating sandbox resources" text="Creating sandbox resources"
// description={ description={
// isDeploymentActive isDeploymentActive
// ? "Preparing server networking..." ? "Preparing server networking..."
// : isServiceRunning : isServiceRunning
// ? "Initializing server, this could take a minute..." ? "Initializing server, this could take a minute..."
// : "Requesting your server creation..." : "Requesting your server creation..."
// } }
// /> />
// ); );
return ( return (
<CodeEditor <CodeEditor ip={taskIp} userData={userData} sandboxData={sandboxData} />
ip={"localhost"}
// ip={taskIp}
userData={userData}
sandboxData={sandboxData}
/>
); );
} }

View File

@ -9,7 +9,7 @@ import {
TerminalSquare, TerminalSquare,
UnfoldVertical, UnfoldVertical,
} from "lucide-react"; } from "lucide-react";
import { useRef } from "react"; import { useRef, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
export default function PreviewWindow({ export default function PreviewWindow({
@ -22,6 +22,7 @@ export default function PreviewWindow({
ip: string; ip: string;
}) { }) {
const ref = useRef<HTMLIFrameElement>(null); const ref = useRef<HTMLIFrameElement>(null);
const [iframeKey, setIframeKey] = useState(0);
return ( return (
<> <>
@ -33,9 +34,9 @@ export default function PreviewWindow({
<div className="h-8 rounded-md px-3 bg-secondary flex items-center w-full justify-between"> <div className="h-8 rounded-md px-3 bg-secondary flex items-center w-full justify-between">
<div className="text-xs"> <div className="text-xs">
Preview Preview
<span className="inline-block ml-2 items-center font-mono text-muted-foreground"> {/* <span className="inline-block ml-2 items-center font-mono text-muted-foreground">
localhost:8000 localhost:8000
</span> </span> */}
</div> </div>
<div className="flex space-x-1 translate-x-1"> <div className="flex space-x-1 translate-x-1">
{collapsed ? ( {collapsed ? (
@ -45,13 +46,13 @@ export default function PreviewWindow({
) : ( ) : (
<> <>
{/* Todo, make this open inspector */} {/* Todo, make this open inspector */}
<PreviewButton disabled onClick={() => {}}> {/* <PreviewButton disabled onClick={() => {}}>
<TerminalSquare className="w-4 h-4" /> <TerminalSquare className="w-4 h-4" />
</PreviewButton> </PreviewButton> */}
<PreviewButton <PreviewButton
onClick={() => { onClick={() => {
navigator.clipboard.writeText(`http://${ip}:8000`); navigator.clipboard.writeText(`http://${ip}:3000`);
toast.info("Copied preview link to clipboard"); toast.info("Copied preview link to clipboard");
}} }}
> >
@ -59,9 +60,10 @@ export default function PreviewWindow({
</PreviewButton> </PreviewButton>
<PreviewButton <PreviewButton
onClick={() => { onClick={() => {
if (ref.current) { // if (ref.current) {
ref.current.contentWindow?.location.reload(); // ref.current.contentWindow?.location.reload();
} // }
setIframeKey((prev) => prev + 1);
}} }}
> >
<RotateCw className="w-3 h-3" /> <RotateCw className="w-3 h-3" />
@ -74,10 +76,11 @@ export default function PreviewWindow({
{collapsed ? null : ( {collapsed ? null : (
<div className="w-full grow rounded-md overflow-hidden bg-foreground"> <div className="w-full grow rounded-md overflow-hidden bg-foreground">
<iframe <iframe
key={iframeKey}
ref={ref} ref={ref}
width={"100%"} width={"100%"}
height={"100%"} height={"100%"}
src={`http://${ip}:8000`} src={`http://${ip}:3000`}
/> />
</div> </div>
)} )}

View File

@ -8,18 +8,12 @@ import { Loader2, Plus, SquareTerminal, TerminalSquare } from "lucide-react";
import { Socket } from "socket.io-client"; import { Socket } from "socket.io-client";
import { toast } from "sonner"; import { toast } from "sonner";
import EditorTerminal from "./terminal"; import EditorTerminal from "./terminal";
import { useState } from "react";
export default function Terminals({ export default function Terminals({
terminals, terminals,
setTerminals, setTerminals,
activeTerminalId,
setActiveTerminalId,
socket, socket,
activeTerminal,
creatingTerminal,
setCreatingTerminal,
closingTerminal,
setClosingTerminal,
}: { }: {
terminals: { id: string; terminal: Terminal | null }[]; terminals: { id: string; terminal: Terminal | null }[];
setTerminals: React.Dispatch< setTerminals: React.Dispatch<
@ -30,20 +24,13 @@ export default function Terminals({
}[] }[]
> >
>; >;
activeTerminalId: string;
setActiveTerminalId: React.Dispatch<React.SetStateAction<string>>;
socket: Socket; socket: Socket;
activeTerminal:
| {
id: string;
terminal: Terminal | null;
}
| undefined;
creatingTerminal: boolean;
setCreatingTerminal: React.Dispatch<React.SetStateAction<boolean>>;
closingTerminal: string;
setClosingTerminal: React.Dispatch<React.SetStateAction<string>>;
}) { }) {
const [activeTerminalId, setActiveTerminalId] = useState("");
const [creatingTerminal, setCreatingTerminal] = useState(false);
const [closingTerminal, setClosingTerminal] = useState("");
const activeTerminal = terminals.find((t) => t.id === activeTerminalId);
return ( return (
<> <>
<div className="h-10 w-full overflow-auto flex gap-2 shrink-0 tab-scroll"> <div className="h-10 w-full overflow-auto flex gap-2 shrink-0 tab-scroll">