diff --git a/app/src/utils/session.js b/app/src/utils/session.js
index 0869c70..65c2dba 100644
--- a/app/src/utils/session.js
+++ b/app/src/utils/session.js
@@ -15,6 +15,7 @@ class SessionManager {
})
)
this.pwd = ref('')
+ this.status = ref('inactive')
}
getSession() {
@@ -26,6 +27,7 @@ class SessionManager {
this.session.value = session
this.graph.value = new FileGraph(session.graph)
this.hints.value = session.hints
+ this.status.value = session.status
}
handleGraphUpdate(event) {
@@ -37,8 +39,12 @@ class SessionManager {
}
}
- handleHintUpdate(event) {
- this.hints.value = [...this.hints.value, ...event]
+ handleHintUpdate(hints) {
+ this.hints.value = [...this.hints.value, ...hints]
+ }
+
+ handleStatusUpdate(status) {
+ this.status.value = status
}
setTasks(tasks) {
diff --git a/app/src/views/GamePage.vue b/app/src/views/GamePage.vue
index c92f8f7..6312731 100644
--- a/app/src/views/GamePage.vue
+++ b/app/src/views/GamePage.vue
@@ -1,5 +1,5 @@
@@ -48,6 +45,12 @@ onMounted(async () => {
+
+
diff --git a/docker-compose.yml b/docker-compose.yml
index d751e4f..1508496 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -36,7 +36,7 @@ services:
- BASE_URL=http://localhost:5173
- MONGO_URL=mongodb://db:27017/odyssey-test
- DOCKER_NETWORK=linux-odyssey-players
- # - HOST_PWD=${PWD}
+ - HOST_PWD=${PWD}
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}
diff --git a/packages/container/cli.js b/packages/container/cli.js
index a6f71d3..2165189 100644
--- a/packages/container/cli.js
+++ b/packages/container/cli.js
@@ -2,6 +2,7 @@
const fs = require('fs').promises
const { exit } = require('process')
const minimist = require('minimist')
+const axios = require('axios')
const { colorize, printResponses } = require('./print.js')
const discoverFiles = require('./discover.js')
@@ -40,6 +41,13 @@ async function main() {
} = process.env
if (!CMD_NAME) exit(0)
+ const api = axios.create({
+ baseURL: `${API_ENDPOINT}/api/v1`,
+ headers: {
+ Authorization: `Bearer ${TOKEN}`,
+ },
+ })
+
const additionalData = await handleCommand(CMD_NAME)
const output = await readOrNone(CMD_OUTPUT_FILE)
@@ -53,24 +61,19 @@ async function main() {
...additionalData,
}
try {
- const res = await fetch(`${API_ENDPOINT}/api/v1/commands`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- Authorization: `Bearer ${TOKEN}`,
- },
- body: JSON.stringify(payload),
- })
- const data = await res.json()
- if (data.responses) {
- await printResponses(data.responses, 60)
+ const res = await api.post('/commands', payload)
+ if (!res.data) return
+ const { responses, hints, end } = res.data
+ if (responses) {
+ await printResponses(responses, 60)
+ await api.post('/commands/completed')
}
- if (data.hints) {
- for (const hint of data.hints) {
+ if (hints) {
+ for (const hint of hints) {
console.log(colorize(hint, 'yellow'))
}
}
- if (data.end) {
+ if (end) {
console.log(colorize('Quest completed!', 'blue'))
}
} catch (err) {
diff --git a/packages/container/package.json b/packages/container/package.json
index 2c6bc8a..c04fd58 100644
--- a/packages/container/package.json
+++ b/packages/container/package.json
@@ -4,7 +4,7 @@
"main": "index.js",
"license": "MIT",
"dependencies": {
- "chokidar": "^3.5.3",
+ "axios": "^1.6.0",
"minimist": "^1.2.8"
}
}
diff --git a/server/src/api/controllers/commandController.js b/server/src/api/controllers/commandController.js
index 36f998a..f3af3d7 100644
--- a/server/src/api/controllers/commandController.js
+++ b/server/src/api/controllers/commandController.js
@@ -1,6 +1,8 @@
-/* eslint-disable import/prefer-default-export */
import { Command, Session } from '@linux-odyssey/models'
import CommandHandler from '../../game/commandHandler.js'
+import { pushToSession } from '../socket.js'
+
+const commandCompleteCallbacks = new Map()
export async function newCommand(req, res) {
console.log('new command:', req.body)
@@ -44,8 +46,35 @@ export async function newCommand(req, res) {
if (response) {
c.stage = response.stage
await c.save()
+ commandCompleteCallbacks.set(session.id, response.callback)
+ pushToSession(session.id, 'status', 'pending')
}
res.status(201).json(response)
await session.save()
}
+
+export async function completedCommand(req, res) {
+ const sessionId = req.user.session_id
+
+ const session = await Session.findById(sessionId)
+
+ if (!session) {
+ res.status(404).json({ message: 'session not found' })
+ return
+ }
+
+ if (session.status === 'inactive') {
+ res.status(400).json({ message: 'session is not active' })
+ return
+ }
+
+ const callback = commandCompleteCallbacks.get(session.id)
+ if (!callback) {
+ res.status(400).json({ message: 'no callback found' })
+ return
+ }
+ callback()
+ commandCompleteCallbacks.delete(session.id)
+ res.json({ message: 'ok' })
+}
diff --git a/server/src/api/controllers/sessionController.js b/server/src/api/controllers/sessionController.js
index 6cdb4df..51f8e69 100644
--- a/server/src/api/controllers/sessionController.js
+++ b/server/src/api/controllers/sessionController.js
@@ -44,6 +44,12 @@ export async function createSession(req, res) {
return
}
+ // deactive all active sessions
+ await Session.updateMany(
+ { user: req.user._id, quest, status: 'active' },
+ { status: 'inactive' }
+ )
+
try {
const container = await createContainer(
`quest-${quest.id}-${req.user.username}-${Date.now()}`
diff --git a/server/src/api/routes/commands.js b/server/src/api/routes/commands.js
index 5eeef05..eb116c3 100644
--- a/server/src/api/routes/commands.js
+++ b/server/src/api/routes/commands.js
@@ -4,5 +4,6 @@ import * as commandController from '../controllers/commandController.js'
const router = Router()
router.post('/', commandController.newCommand)
+router.post('/completed', commandController.completedCommand)
export default router
diff --git a/server/src/api/routes/index.js b/server/src/api/routes/index.js
index 53a9c9f..fde9932 100644
--- a/server/src/api/routes/index.js
+++ b/server/src/api/routes/index.js
@@ -19,6 +19,7 @@ router.use('/sessions', authRequired, sessions)
router.use(
'/commands',
passport.authenticate('jwt', { session: false }),
+ authRequired,
commands
)
diff --git a/server/src/game/sessionHandler.js b/server/src/game/sessionHandler.js
index a6a91f8..6107305 100644
--- a/server/src/game/sessionHandler.js
+++ b/server/src/game/sessionHandler.js
@@ -34,7 +34,6 @@ export default class SessionHandler {
addNewTasks() {
const newTasks = this.getNewTasks()
this.session.tasks.push(...newTasks)
- pushToSession(this.session.id, 'tasks', this.session.tasks)
}
execute(stage) {
@@ -45,12 +44,10 @@ export default class SessionHandler {
})
this.session.hints.push(...stage.hints)
- pushToSession(this.session.id, 'hints', stage.hints)
if (stage.id === 'END') {
this.session.status = 'finished'
this.session.finishedAt = new Date()
- pushToSession(this.session.id, 'status', 'finished')
}
this.addNewTasks()
@@ -58,6 +55,11 @@ export default class SessionHandler {
return {
responses: stage.responses,
hints: stage.hints,
+ callback: () => {
+ pushToSession(this.session.id, 'tasks', this.session.tasks)
+ pushToSession(this.session.id, 'hints', stage.hints)
+ pushToSession(this.session.id, 'status', this.session.status)
+ },
}
}
}
diff --git a/yarn.lock b/yarn.lock
index 0046d79..9e4e5e4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1407,6 +1407,15 @@ axios@^1.5.0:
form-data "^4.0.0"
proxy-from-env "^1.1.0"
+axios@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102"
+ integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==
+ dependencies:
+ follow-redirects "^1.15.0"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
babel-jest@^29.6.1:
version "29.6.1"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.1.tgz#a7141ad1ed5ec50238f3cd36127636823111233a"