mirror of
https://github.com/biersoeckli/QuickStack.git
synced 2025-12-31 08:19:54 -06:00
fixed terminal stuff
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}} >
|
||||
<Button variant="secondary">
|
||||
Terminal
|
||||
<Terminal /> Terminal
|
||||
</Button>
|
||||
</TerminalDialog>
|
||||
</div>
|
||||
|
||||
@@ -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 <>
|
||||
<div className="space-y-4">
|
||||
{!sessionTerminalInfo && <>
|
||||
{!sessionTerminalInfo ? <>
|
||||
<div className="flex gap-4">
|
||||
<Button variant="secondary" onClick={() => startTerminalSession('sh')}>Start sh</Button>
|
||||
<Button variant="secondary" onClick={() => startTerminalSession('bash')}>Start bash</Button>
|
||||
</div>
|
||||
</>}
|
||||
<div ref={terminalWindow} ></div>
|
||||
</> : <Button variant="secondary" onClick={() => disconnectTerminalSession()}>Disconnect Session</Button>}
|
||||
<div ref={terminalWindow}></div>
|
||||
|
||||
</div>
|
||||
</>;
|
||||
|
||||
@@ -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<DefaultEventsMap, DefaultEventsMap, DefaultEventsMap, any>,
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user