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({
where: (user, { eq }) => eq(user.id, id),
with: {
sandbox: true,
sandbox: {
orderBy: (sandbox, { desc }) => [desc(sandbox.createdAt)],
},
usersToSandboxes: true,
},
});

View File

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

View File

@ -51,6 +51,9 @@ const terminals: {
const dirName = path.join(__dirname, "..");
io.use(async (socket, next) => {
console.log("Middleware");
const handshakeSchema = z.object({
userId: z.string(),
sandboxId: z.string(),
@ -58,12 +61,11 @@ const handshakeSchema = z.object({
transport: z.string(),
});
io.use(async (socket, next) => {
const q = socket.handshake.query;
const parseQuery = handshakeSchema.safeParse(q);
if (!parseQuery.success) {
("Invalid request.");
console.log("Invalid request.");
next(new Error("Invalid request."));
return;
}
@ -75,6 +77,7 @@ io.use(async (socket, next) => {
const dbUserJSON = (await dbUser.json()) as User;
if (!dbUserJSON) {
console.log("DB error.");
next(new Error("DB error."));
return;
}
@ -85,6 +88,7 @@ io.use(async (socket, next) => {
);
if (!sandbox && !sharedSandboxes) {
console.log("Invalid credentials.");
next(new Error("Invalid credentials."));
return;
}
@ -145,6 +149,7 @@ io.on("connection", async (socket) => {
// todo: send diffs + debounce for efficiency
socket.on("saveFile", async (fileId: string, body: string) => {
console.log("save");
try {
await saveFileRL.consume(data.userId, 1);
@ -470,5 +475,5 @@ io.on("connection", async (socket) => {
});
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({
plugins: [react()],
server: {
port: 8000,
},
port: 3000,
host: "0.0.0.0",
}
})
`,
},
@ -87,10 +88,12 @@ export default defineConfig({
flex-direction: column;
align-items: center;
justify-content: center;
font-family: sans-serif;
}
h1 {
color: #fff;
color: #000;
margin: 0;
}

View File

@ -90,10 +90,6 @@ export default function CodeEditor({
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 clerk = useClerk();
@ -752,14 +748,7 @@ export default function CodeEditor({
<Terminals
terminals={terminals}
setTerminals={setTerminals}
activeTerminalId={activeTerminalId}
setActiveTerminalId={setActiveTerminalId}
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">

View File

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

View File

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

View File

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