diff --git a/Dockerfile b/Dockerfile
index 6382fac..f37c069 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -7,7 +7,7 @@ RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
-COPY bun.lockb package.json ./
+COPY yarn.lock package.json ./
RUN yarn install
diff --git a/package.json b/package.json
index 2e7471e..1b6328d 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"private": true,
"scripts": {
"dev": "next dev",
- "dev-live": "tsc src/server.ts",
+ "dev-live": "tsc --project tsconfig.server.json && node dist/server.js",
"build": "next build && tsc --project tsconfig.server.json",
"start": "next start",
"start-prod": "cross-env NODE_ENV=production node dist/server.js",
diff --git a/src/app/project/app/[appId]/overview/logs.tsx b/src/app/project/app/[appId]/overview/logs.tsx
index bd15cd8..3a1ea9a 100644
--- a/src/app/project/app/[appId]/overview/logs.tsx
+++ b/src/app/project/app/[appId]/overview/logs.tsx
@@ -9,7 +9,7 @@ import FullLoadingSpinner from "@/components/ui/full-loading-spinnter";
import { toast } from "sonner";
import { LogsDialog } from "@/components/custom/logs-overlay";
import { Button } from "@/components/ui/button";
-import { Expand, SquareArrowUp, SquareArrowUpRight } from "lucide-react";
+import { Expand, SquareArrowUp, SquareArrowUpRight, Terminal } from "lucide-react";
import { TerminalDialog } from "./terminal-overlay";
export default function Logs({
@@ -81,7 +81,7 @@ export default function Logs({
namespace: app.projectId
}} >
diff --git a/src/app/project/app/[appId]/overview/terminal-streamed.tsx b/src/app/project/app/[appId]/overview/terminal-streamed.tsx
index 33ebb14..571f604 100644
--- a/src/app/project/app/[appId]/overview/terminal-streamed.tsx
+++ b/src/app/project/app/[appId]/overview/terminal-streamed.tsx
@@ -46,34 +46,31 @@ export default function TerminalStreamed({
});
podTerminalSocket.on(terminalOutputKey, (data: string) => {
- console.log('Received data:', data);
term.write(data);
});
podTerminalSocket.emit('openTerminal', termInfo);
- term.write('Terminal is ready');
setTerminal(term);
setSessionTerminalInfo(termInfo);
};
-
- useEffect(() => {
- return () => {
- console.log('Disconnecting from terminal...');
- //terminal?.dispose();
- //if (sessionTerminalInfo) podTerminalSocket.emit('closeTerminal', sessionTerminalInfo);
- };
- });
+ const disconnectTerminalSession = () => {
+ terminal?.dispose();
+ if (sessionTerminalInfo) {
+ podTerminalSocket.emit('closeTerminal', sessionTerminalInfo);
+ setSessionTerminalInfo(undefined);
+ }
+ }
return <>
- {!sessionTerminalInfo && <>
+ {!sessionTerminalInfo ? <>
- >}
-
+ > :
}
+
>;
diff --git a/src/server/services/terminal.service.ts b/src/server/services/terminal.service.ts
index e522978..3c6d5f6 100644
--- a/src/server/services/terminal.service.ts
+++ b/src/server/services/terminal.service.ts
@@ -5,6 +5,7 @@ import * as k8s from '@kubernetes/client-node';
import stream from 'stream';
import { StreamUtils } from "../../shared/utils/stream.utils";
import WebSocket from "ws";
+import setupPodService from "./setup-services/setup-pod.service";
interface TerminalStrean {
stdoutStream: stream.PassThrough;
@@ -33,68 +34,60 @@ export class TerminalService {
const streamInputKey = StreamUtils.getInputStreamName(terminalInfo);
const streamOutputKey = StreamUtils.getOutputStreamName(terminalInfo);
- /*const podReachable = await setupPodService.waitUntilPodIsRunningFailedOrSucceded(terminalInfo.namespace, terminalInfo.podName);
+ const podReachable = await setupPodService.waitUntilPodIsRunningFailedOrSucceded(terminalInfo.namespace, terminalInfo.podName);
if (!podReachable) {
socket.emit(streamOutputKey, 'Pod is not reachable.');
return;
- }*/
+ }
const exec = new k8s.Exec(k3s.getKubeConfig());
const stdoutStream = new stream.PassThrough();
const stderrStream = new stream.PassThrough();
const stdinStream = new stream.PassThrough();
- console.log('starting exec')
- await exec.exec(
+
+ const socketStreamInfo = {
+ stdoutStream,
+ stderrStream,
+ stdinStream,
+ terminalSessionKey: terminalInfo.terminalSessionKey ?? '',
+ } as TerminalStrean;
+ streamsOfSocket.push(socketStreamInfo);
+
+ const websocket = await exec.exec(
terminalInfo.namespace,
terminalInfo.podName,
terminalInfo.containerName,
[terminalInfo.terminalType === 'sh' ? '/bin/sh' : '/bin/bash'],
- /* process.stdout,
- process.stderr,
- process.stdin,*/
stdoutStream,
stderrStream,
stdinStream,
- false /* tty */,
+ true /* tty */,
(status: k8s.V1Status) => {
console.log('[EXIT] Exited with status:');
console.log(JSON.stringify(status, null, 2));
- stderrStream!.end();
- stdoutStream!.end();
- stdinStream!.end();
+ if (status.status === 'Failure') {
+ socket.emit(streamOutputKey, `\n[ERROR] Error while opening Terminal session\n`);
+ socket.emit(streamOutputKey, `\n${status.message}\n`);
+ } else {
+ socket.emit(streamOutputKey, `\n[INFO] Terminal session closed\n`);
+ }
+ this.cleanupLogStream(socketStreamInfo);
},
);
+ socketStreamInfo.websocket = websocket;
stdoutStream.on('data', (chunk) => {
- console.log(chunk)
socket.emit(streamOutputKey, chunk.toString());
});
- stdoutStream.on('error', (error) => {
- console.error("Error in terminal stream:", error);
- });
- stdoutStream.on('end', () => {
- //console.log(`[END] Log stream ended for ${streamKey} by ${streamEndedByClient ? 'client' : 'server'}`);
-
- });
-
stderrStream.on('data', (chunk) => {
console.log(chunk)
socket.emit(streamOutputKey, chunk.toString());
});
socket.on(streamInputKey, (data) => {
- console.log('Received data:', data);
stdinStream!.write(data);
});
- streamsOfSocket.push({
- stdoutStream,
- stderrStream,
- stdinStream,
- terminalSessionKey: terminalInfo.terminalSessionKey ?? '',
- //websocket
- });
-
console.log(`Client ${socket.id} joined terminal stream for:`);
console.log(`Input: ${streamInputKey}`);
console.log(`Output: ${streamOutputKey}`);
@@ -109,49 +102,26 @@ export class TerminalService {
const streams = streamsOfSocket.find(stream => stream.terminalSessionKey === terminalInfo.terminalSessionKey);
if (streams) {
- this.deleteLogStream(streams);
+ this.cleanupLogStream(streams);
}
});
socket.on('disconnecting', () => {
// Stop all log streams for this client
for (const stream of streamsOfSocket) {
- this.deleteLogStream(stream);
+ this.cleanupLogStream(stream);
}
});
}
- private deleteLogStream(streams: TerminalStrean) {
- /* streams.stderrStream.end();
- streams.stdoutStream.end();
- streams.stdinStream.end();
- streams.websocket.close();*/
-
- console.log(`Stopped log stream for ${streams.terminalSessionKey}.`);
+ private cleanupLogStream(stream: TerminalStrean) {
+ stream.stderrStream.end();
+ stream.stdoutStream.end();
+ stream.stdinStream.end();
+ stream.websocket?.close();
+ console.log(`Stopped terminal stream for ${stream.terminalSessionKey}.`);
}
- /*
- private async createLogStreamForPod(socket: Socket,
- streamKey: string, inputInfo: TerminalSetupInfoModel) {
-
-
-
- logStream.on('data', (chunk) => {
- socket.emit(streamKey, chunk.toString());
- });
-
- logStream.on('data', (chunk) => {
- socket.to(streamKey).emit(`${streamKey}`, chunk.toString());
- });
-
- let k3sStreamRequest = await k3s.log.log(app.projectId, pod.podName, pod.containerName, logStream, {
- follow: true,
- pretty: false,
- tailLines: 100,
- });
- const retVal = { logStream, clients: 0, k3sStreamRequest };
- return retVal;
- }*/
}
const terminalService = new TerminalService();