mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-06 03:20:13 +08:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e37b13d99 | ||
|
|
b2a251576c | ||
|
|
8cc006e3a4 | ||
|
|
d6ae6d818d | ||
|
|
6692ae2b9b | ||
|
|
fab02d03a9 | ||
|
|
9e44ebe415 | ||
|
|
019caf58e4 |
No files matched your search
+1
-1
@@ -3,6 +3,7 @@ PORT=3000
|
|||||||
BASE_URL=https://example.com
|
BASE_URL=https://example.com
|
||||||
SECRET_KEY=YOU_SHOULD_CHANGE_THIS
|
SECRET_KEY=YOU_SHOULD_CHANGE_THIS
|
||||||
BACKEND_URL=http://backend:3000
|
BACKEND_URL=http://backend:3000
|
||||||
|
DOCKER_NETWORK=linux-odyssey-players
|
||||||
|
|
||||||
MONGO_ROOT_PASSWORD=adminpassword
|
MONGO_ROOT_PASSWORD=adminpassword
|
||||||
MONGO_USER=commander
|
MONGO_USER=commander
|
||||||
@@ -29,7 +30,6 @@ ADMIN_PORT=3001
|
|||||||
# GITHUB_CLIENT_SECRET=
|
# GITHUB_CLIENT_SECRET=
|
||||||
# SURVEY_URL=
|
# SURVEY_URL=
|
||||||
# BUG_REPORT_URL=
|
# BUG_REPORT_URL=
|
||||||
# DOCKER_NETWORK=
|
|
||||||
|
|
||||||
# SURVEY_URL=
|
# SURVEY_URL=
|
||||||
# BUG_REPORT_URL=
|
# BUG_REPORT_URL=
|
||||||
|
|||||||
+1
-1
@@ -3,6 +3,7 @@ PORT=3000
|
|||||||
BASE_URL=http://localhost:5173
|
BASE_URL=http://localhost:5173
|
||||||
MONGO_URL=mongodb://localhost:27017/odyssey-test
|
MONGO_URL=mongodb://localhost:27017/odyssey-test
|
||||||
SECRET_KEY=sample-secret
|
SECRET_KEY=sample-secret
|
||||||
|
DOCKER_NETWORK=linux-odyssey-players-dev
|
||||||
|
|
||||||
# Optional
|
# Optional
|
||||||
# BACKEND_URL=http://host.docker.internal:3000
|
# BACKEND_URL=http://host.docker.internal:3000
|
||||||
@@ -17,7 +18,6 @@ SECRET_KEY=sample-secret
|
|||||||
# GITHUB_CLIENT_SECRET=
|
# GITHUB_CLIENT_SECRET=
|
||||||
# SURVEY_URL=
|
# SURVEY_URL=
|
||||||
# BUG_REPORT_URL=
|
# BUG_REPORT_URL=
|
||||||
# DOCKER_NETWORK=
|
|
||||||
|
|
||||||
# SURVEY_URL=
|
# SURVEY_URL=
|
||||||
# BUG_REPORT_URL=
|
# BUG_REPORT_URL=
|
||||||
|
|||||||
+3
-4
@@ -13,7 +13,7 @@ services:
|
|||||||
base:
|
base:
|
||||||
image: linuxodyssey/quest-base
|
image: linuxodyssey/quest-base
|
||||||
networks:
|
networks:
|
||||||
- players
|
- players-dev
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./quests/Dockerfile
|
dockerfile: ./quests/Dockerfile
|
||||||
@@ -22,7 +22,6 @@ services:
|
|||||||
|
|
||||||
networks:
|
networks:
|
||||||
internal:
|
internal:
|
||||||
players:
|
players-dev:
|
||||||
name: linux-odyssey-players
|
name: linux-odyssey-players-dev
|
||||||
internal: false
|
internal: false
|
||||||
external: true
|
|
||||||
+29
-8
@@ -1,24 +1,39 @@
|
|||||||
PROMPT='%F{2}%n%f:%F{6}%~%f $ '
|
PROMPT='%F{2}%n%f:%F{6}%~%f $ '
|
||||||
unsetopt CASE_GLOB
|
unsetopt CASE_GLOB
|
||||||
setopt CHASE_LINKS
|
setopt CHASE_LINKS
|
||||||
emulate bash
|
# emulate bash
|
||||||
|
|
||||||
set +o prompt_cr
|
set +o prompt_cr
|
||||||
|
|
||||||
preexec() {
|
preexec() {
|
||||||
export CMD_START_TIME=$(date +%s%N) # capture start time
|
export CMD_START_TIME=$(date +%s%N) # capture start time
|
||||||
export CMD_NAME=$1 # capture command
|
export CMD_NAME="$1" # capture command
|
||||||
|
export CMD_PID=$$
|
||||||
|
|
||||||
# A list of interactive commands
|
# # A list of interactive commands
|
||||||
interactive_commands=("vim" "nano" "top" "ssh" "less" "zsh" "bash")
|
# readlink /proc/$PPID/exe
|
||||||
|
interactive_commands=("vim" "nano" "top" "ssh" "less" "zsh" "bash" "script" "exec")
|
||||||
|
# # if [[ $CMD_EXECUTED = 1 ]]; then
|
||||||
|
# # export CMD_EXECUTED=0
|
||||||
|
# # return
|
||||||
|
# # fi
|
||||||
|
|
||||||
# Check if the command is in the list of interactive commands
|
# # Check if the command is in the list of interactive commands
|
||||||
if [[ " ${interactive_commands[@]} " =~ " $1 " ]]; then
|
if [[ " ${interactive_commands[@]} " =~ " $1 " ]]; then
|
||||||
# If it is, just execute it normally
|
# If it is, just execute it normally
|
||||||
exec
|
# exec
|
||||||
|
# echo IF
|
||||||
|
return
|
||||||
else
|
else
|
||||||
# If it's not, execute it and redirect its output to a file
|
# If it's not, execute it and redirect its output to a file
|
||||||
exec > >(tee /tmp/cmd.out) 2> >(tee /tmp/cmd.error >&2)
|
# exec > >(tee /tmp/cmd.out) 2> >(tee /tmp/cmd.error >&2)
|
||||||
|
# echo ELSE
|
||||||
|
# export CMD_EXECUTED=1
|
||||||
|
# eval >&1 >/tmp/cmd.out
|
||||||
|
# exec >&1
|
||||||
|
# exec
|
||||||
|
script --quiet -O /tmp/cmd.out -c "$CMD_NAME"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +44,12 @@ precmd() {
|
|||||||
export CMD_ERROR_FILE=/tmp/cmd.error
|
export CMD_ERROR_FILE=/tmp/cmd.error
|
||||||
|
|
||||||
# Now run your Node.js script with the result as an argument
|
# Now run your Node.js script with the result as an argument
|
||||||
node /usr/local/lib/container/cli.js; rm /tmp/cmd.out /tmp/cmd.error 2>/dev/null
|
node /usr/local/lib/container/cli.js
|
||||||
|
if [[ -n $CMD_PID ]]; then
|
||||||
|
# echo $CMD_PID
|
||||||
|
# kill $CMD_PID
|
||||||
|
fi
|
||||||
|
# rm /tmp/cmd.out /tmp/cmd.error 2>/dev/null
|
||||||
|
|
||||||
# Reset variables
|
# Reset variables
|
||||||
unset CMD_START_TIME
|
unset CMD_START_TIME
|
||||||
@@ -38,5 +58,6 @@ precmd() {
|
|||||||
unset CMD_OUTPUT_FILE
|
unset CMD_OUTPUT_FILE
|
||||||
unset CMD_ERROR_FILE
|
unset CMD_ERROR_FILE
|
||||||
unset CMD_NAME
|
unset CMD_NAME
|
||||||
|
export CMD_EXECUTED=0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^cp hello.txt hello2.txt$
|
- ^cp hello.txt hello2.txt$
|
||||||
files:
|
files:
|
||||||
- path: hello2.txt
|
- path: /home/commander/hello2.txt
|
||||||
type: file
|
type: file
|
||||||
exceptions:
|
exceptions:
|
||||||
- condition:
|
- condition:
|
||||||
@@ -224,7 +224,7 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^cp world.txt world2.txt$
|
- ^cp world.txt world2.txt$
|
||||||
files:
|
files:
|
||||||
- path: world2.txt
|
- path: /home/commander/world2.txt
|
||||||
type: file
|
type: file
|
||||||
exceptions:
|
exceptions:
|
||||||
- condition:
|
- condition:
|
||||||
@@ -292,9 +292,9 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^cp
|
- ^cp
|
||||||
files:
|
files:
|
||||||
- path: notes2
|
- path: /home/commander/notes2
|
||||||
type: directory
|
type: directory
|
||||||
- path: notes2/note.txt
|
- path: /home/commander/notes2/note.txt
|
||||||
type: file
|
type: file
|
||||||
exceptions:
|
exceptions:
|
||||||
- condition:
|
- condition:
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ stages:
|
|||||||
- ls
|
- ls
|
||||||
condition:
|
condition:
|
||||||
files:
|
files:
|
||||||
- path: hello.txt
|
- path: /home/commander/hello.txt
|
||||||
type: file
|
type: file
|
||||||
exceptions:
|
exceptions:
|
||||||
- condition:
|
- condition:
|
||||||
files:
|
files:
|
||||||
- path: hello$
|
- path: /home/commander/hello
|
||||||
type: file
|
type: file
|
||||||
responses:
|
responses:
|
||||||
- type: narrative
|
- type: narrative
|
||||||
@@ -107,12 +107,12 @@ stages:
|
|||||||
- ls-touch
|
- ls-touch
|
||||||
condition:
|
condition:
|
||||||
files:
|
files:
|
||||||
- path: world.txt
|
- path: /home/commander/world.txt
|
||||||
type: file
|
type: file
|
||||||
exceptions:
|
exceptions:
|
||||||
- condition:
|
- condition:
|
||||||
files:
|
files:
|
||||||
- path: world$
|
- path: /home/commander/world
|
||||||
type: file
|
type: file
|
||||||
responses:
|
responses:
|
||||||
- type: narrative
|
- type: narrative
|
||||||
@@ -154,7 +154,7 @@ stages:
|
|||||||
- ls-2
|
- ls-2
|
||||||
condition:
|
condition:
|
||||||
files:
|
files:
|
||||||
- path: notes
|
- path: /home/commander/notes
|
||||||
type: folder
|
type: folder
|
||||||
responses:
|
responses:
|
||||||
- type: narrative
|
- type: narrative
|
||||||
@@ -203,7 +203,7 @@ stages:
|
|||||||
- cd-notes
|
- cd-notes
|
||||||
condition:
|
condition:
|
||||||
files:
|
files:
|
||||||
- path: notes/note.txt
|
- path: /home/commander/notes/note.txt
|
||||||
type: file
|
type: file
|
||||||
responses:
|
responses:
|
||||||
- type: narrative
|
- type: narrative
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^mv hello.txt notes$
|
- ^mv hello.txt notes$
|
||||||
files:
|
files:
|
||||||
- path: notes/hello.txt
|
- path: /home/commander/notes/hello.txt
|
||||||
type: file
|
type: file
|
||||||
- path: hello.txt
|
- path: /home/commander/hello.txt
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- type: narrative
|
- type: narrative
|
||||||
@@ -106,9 +106,9 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^mv
|
- ^mv
|
||||||
files:
|
files:
|
||||||
- path: wow.txt
|
- path: /home/commander/wow.txt
|
||||||
type: file
|
type: file
|
||||||
- path: world.txt
|
- path: /home/commander/world.txt
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- type: narrative
|
- type: narrative
|
||||||
@@ -148,9 +148,9 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^mv
|
- ^mv
|
||||||
files:
|
files:
|
||||||
- path: docs
|
- path: /home/commander/docs
|
||||||
type: directory
|
type: directory
|
||||||
- path: notes
|
- path: /home/commander/notes
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- type: narrative
|
- type: narrative
|
||||||
@@ -187,9 +187,9 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^mv
|
- ^mv
|
||||||
files:
|
files:
|
||||||
- path: hi.txt
|
- path: /home/commander/hi.txt
|
||||||
type: file
|
type: file
|
||||||
- path: docs/hello.txt
|
- path: /home/commander/docs/hello.txt
|
||||||
exists: false
|
exists: false
|
||||||
exceptions:
|
exceptions:
|
||||||
- condition:
|
- condition:
|
||||||
|
|||||||
+10
-10
@@ -44,7 +44,7 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^rm\s
|
- ^rm\s
|
||||||
files:
|
files:
|
||||||
- path: hello.txt
|
- path: /home/commander/hello.txt
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- content: |
|
- content: |
|
||||||
@@ -58,7 +58,7 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^ls$
|
- ^ls$
|
||||||
files:
|
files:
|
||||||
- path: hello.txt
|
- path: /home/commander/hello.txt
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- content: |
|
- content: |
|
||||||
@@ -78,9 +78,9 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^rm
|
- ^rm
|
||||||
files:
|
files:
|
||||||
- path: world.txt
|
- path: /home/commander/world.txt
|
||||||
exists: false
|
exists: false
|
||||||
- path: wow.txt
|
- path: /home/commander/wow.txt
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- content: |
|
- content: |
|
||||||
@@ -111,7 +111,7 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^rmdir empty$
|
- ^rmdir empty$
|
||||||
files:
|
files:
|
||||||
- path: empty
|
- path: /home/commander/empty
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- content: |
|
- content: |
|
||||||
@@ -139,7 +139,7 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^rmdir notes$
|
- ^rmdir notes$
|
||||||
files:
|
files:
|
||||||
- path: notes
|
- path: /home/commander/notes
|
||||||
type: folder
|
type: folder
|
||||||
exists: true
|
exists: true
|
||||||
responses:
|
responses:
|
||||||
@@ -161,10 +161,10 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^rm
|
- ^rm
|
||||||
files:
|
files:
|
||||||
- path: notes
|
- path: /home/commander/notes
|
||||||
type: folder
|
type: folder
|
||||||
exists: true
|
exists: true
|
||||||
- path: notes/note.txt
|
- path: /home/commander/notes/note.txt
|
||||||
exists: false
|
exists: false
|
||||||
exceptions:
|
exceptions:
|
||||||
- condition:
|
- condition:
|
||||||
@@ -203,7 +203,7 @@ stages:
|
|||||||
task: 使用 `rmdir` 刪除 `notes` 資料夾
|
task: 使用 `rmdir` 刪除 `notes` 資料夾
|
||||||
condition:
|
condition:
|
||||||
files:
|
files:
|
||||||
- path: notes
|
- path: /home/commander/notes
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- content: |
|
- content: |
|
||||||
@@ -238,7 +238,7 @@ stages:
|
|||||||
command:
|
command:
|
||||||
- ^rm -r trash$
|
- ^rm -r trash$
|
||||||
files:
|
files:
|
||||||
- path: trash
|
- path: /home/commander/trash
|
||||||
exists: false
|
exists: false
|
||||||
responses:
|
responses:
|
||||||
- content: |
|
- content: |
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { asyncHandler } from '../../middleware/error.js'
|
|||||||
|
|
||||||
export const newCommand = asyncHandler(async (req: Request, res: Response) => {
|
export const newCommand = asyncHandler(async (req: Request, res: Response) => {
|
||||||
const { command, pwd, output, error, params } = matchedData(req)
|
const { command, pwd, output, error, params } = matchedData(req)
|
||||||
|
console.log(command, output, error)
|
||||||
|
|
||||||
const { sessionId } = req.user as any
|
const { sessionId } = req.user as any
|
||||||
const session = await Session.findById(sessionId)
|
const session = await Session.findById(sessionId)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ function createConfig() {
|
|||||||
projectRoot,
|
projectRoot,
|
||||||
|
|
||||||
docker: {
|
docker: {
|
||||||
network: get('DOCKER_NETWORK', 'linux-odyssey-players'),
|
network: get('DOCKER_NETWORK', 'linux-odyssey-players-dev'),
|
||||||
defaultImage: get('QUEST_IMAGE', 'linuxodyssey/quest-base'),
|
defaultImage: get('QUEST_IMAGE', 'linuxodyssey/quest-base'),
|
||||||
imagePrefix: get('DOCKER_PREFIX', 'linuxodyssey/quest-'),
|
imagePrefix: get('DOCKER_PREFIX', 'linuxodyssey/quest-'),
|
||||||
mountQuest: process.env.MOUNT_QUEST === 'true',
|
mountQuest: process.env.MOUNT_QUEST === 'true',
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ export async function createContainer(
|
|||||||
imageId: string
|
imageId: string
|
||||||
): Promise<Docker.Container> {
|
): Promise<Docker.Container> {
|
||||||
let binds: string[] = []
|
let binds: string[] = []
|
||||||
|
binds.push(
|
||||||
|
`${config.docker.hostProjectRoot}/quests/.includes/zshrc:/etc/zsh/zshrc`
|
||||||
|
)
|
||||||
if (await questHomeExists(questId)) {
|
if (await questHomeExists(questId)) {
|
||||||
logger.info('Mounting quest home', questId)
|
logger.info('Mounting quest home', questId)
|
||||||
binds.push(
|
binds.push(
|
||||||
@@ -94,20 +97,21 @@ export async function attachContainer(
|
|||||||
config.docker.network
|
config.docker.network
|
||||||
].IPAddress
|
].IPAddress
|
||||||
|
|
||||||
|
let error: Error | null = null
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
try {
|
try {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const stream = await connectToSSH(containerIp, { token })
|
const stream = await connectToSSH(containerIp, { token })
|
||||||
return stream
|
return stream
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Failed to connect to SSH', err)
|
error = err as Error
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
setTimeout(resolve, 1000)
|
setTimeout(resolve, 1000)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error('Failed to connect to SSH')
|
throw new Error('Failed to connect to SSH', { cause: error })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteContainer(id: string) {
|
export async function deleteContainer(id: string) {
|
||||||
|
|||||||
Reference in new issue
Block a user