From 0153eae6737ff51ab9ebb0c559a83f4eee5383b6 Mon Sep 17 00:00:00 2001 From: wancat Date: Fri, 4 Aug 2023 21:21:54 +0800 Subject: [PATCH] feat: new cli client to send and receive msg from api --- docker-compose.build.yml | 7 +++ packages/cli/cli.js | 70 +++++++++++++++++++++++++++ server/quests/helloworld/Dockerfile | 6 ++- server/quests/helloworld/home/.bashrc | 20 +++----- server/src/utils/docker.js | 7 ++- 5 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 docker-compose.build.yml create mode 100644 packages/cli/cli.js diff --git a/docker-compose.build.yml b/docker-compose.build.yml new file mode 100644 index 0000000..c3bcd77 --- /dev/null +++ b/docker-compose.build.yml @@ -0,0 +1,7 @@ +version: '3' +services: + helloworld: + image: lancatlin/linux-odyssey:helloworld + build: + context: . + dockerfile: server/quests/helloworld/Dockerfile diff --git a/packages/cli/cli.js b/packages/cli/cli.js new file mode 100644 index 0000000..f42d495 --- /dev/null +++ b/packages/cli/cli.js @@ -0,0 +1,70 @@ +const readline = require('readline') + +process.stdin.setRawMode(true) + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + terminal: false, +}) + +async function printResponses(responses, delay = 100) { + for (const response of responses) { + await printResponse(response, delay) + } + rl.close() +} + +function waitForEnter() { + return new Promise((resolve) => { + rl.once('line', resolve) + }) +} + +function printResponse(response, delay) { + return new Promise((resolve) => { + let i = 0 + const timer = setInterval(() => { + process.stdout.write(response[i]) + i += 1 + if (i >= response.length) { + clearInterval(timer) + waitForEnter().then(resolve) + } + }, delay) + + waitForEnter().then(() => { + clearInterval(timer) + process.stdout.write(response.slice(i) + '\n') + resolve() + }) + }) +} + +async function request() { + const { API_ENDPOINT, TOKEN, PWD, COMMAND, OUTPUT, EXIT_CODE } = process.env + const payload = { + command: COMMAND, + output: OUTPUT, + exit_code: EXIT_CODE, + token: TOKEN, + pwd: PWD, + } + try { + const res = await fetch(`${API_ENDPOINT}/api/v1/commands`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }) + const data = await res.json() + if (data.responses) { + await printResponses(data.responses, 100) + } + } catch (err) { + console.error(err) + } +} + +request() diff --git a/server/quests/helloworld/Dockerfile b/server/quests/helloworld/Dockerfile index 01f3814..40265a8 100644 --- a/server/quests/helloworld/Dockerfile +++ b/server/quests/helloworld/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:latest +FROM node:latest RUN apt-get update && apt-get install -y \ curl \ @@ -11,6 +11,8 @@ USER rudeus WORKDIR /home/rudeus -COPY ./home /home/rudeus/ +COPY ./server/quests/helloworld/home /home/rudeus/ + +COPY ./packages/cli/cli.js /usr/local/bin/cli.js CMD [ "/bin/bash" ] diff --git a/server/quests/helloworld/home/.bashrc b/server/quests/helloworld/home/.bashrc index 3a0355f..39e6094 100644 --- a/server/quests/helloworld/home/.bashrc +++ b/server/quests/helloworld/home/.bashrc @@ -2,26 +2,20 @@ preexec() { [ -n "$COMP_LINE" ] && return # do nothing if completing [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # do nothing if completing - local command="$BASH_COMMAND" - local pwd="$PWD" + export COMMAND="$BASH_COMMAND" - if [[ $command =~ ^(vim|top|less|more|nano) ]]; then - local payload=$(printf '{"token": "%s", "pwd": "%s", "command": "%s"}' "$TOKEN" "$pwd" "$command") - curl -X POST $API_ENDPOINT/api/v1/commands -H 'accept: */*' -H 'Content-Type: application/json' -d "$payload" + if [[ $COMMAND =~ ^(vim|top|less|more|nano) ]]; then + node /usr/local/bin/cli.js return fi # Execute the command, capture output and exit code - local output=$( { eval $command 2>&1; echo $? > /tmp/exit_code; }) - local exit_code=$(cat /tmp/exit_code) + export OUTPUT=$( { eval $COMMAND 2>&1; echo $? > /tmp/exit_code; }) + export EXIT_CODE=$(cat /tmp/exit_code) - local output_esc=$(echo $output | jq -Rs .) - - # Store command in variable - local payload=$(printf '{"token": "%s", "pwd": "%s", "command": "%s", "exit_code": "%s", "output": %s}' "$TOKEN" "$pwd" "$command" "$exit_code" "$output_esc") - + echo $OUTPUT # Send command to the API - curl -X POST $API_ENDPOINT/api/v1/commands -H 'accept: */*' -H 'Content-Type: application/json' -d "$payload" || echo $payload + node /usr/local/bin/cli.js BASH_COMMAND="" } diff --git a/server/src/utils/docker.js b/server/src/utils/docker.js index 50fe918..cf7ee87 100644 --- a/server/src/utils/docker.js +++ b/server/src/utils/docker.js @@ -3,7 +3,7 @@ import config from '../config.js' const engine = new Docker() -const questPath = '/home/zeko/src/linux-odyssey/server/quests' +const projectPath = '/home/zeko/src/linux-odyssey' const containerOptions = { Image: 'lancatlin/linux-odyssey:helloworld', @@ -17,7 +17,10 @@ const containerOptions = { HostConfig: { Binds: config.isProduction ? [] - : [`${questPath}/helloworld/home:/home/rudeus`], + : [ + `${projectPath}/server/quests/helloworld/home:/home/rudeus`, + `${projectPath}/packages/cli/cli.js:/usr/local/bin/cli.js`, + ], }, }