From c83ca750e19233fe02e43f6ebbf8c27134772649 Mon Sep 17 00:00:00 2001 From: wancat Date: Sat, 22 Jul 2023 16:35:44 +0800 Subject: [PATCH 1/3] Connect to different shell --- server/src/api/socket.js | 2 +- server/src/utils/docker.js | 34 ++++++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/server/src/api/socket.js b/server/src/api/socket.js index d8c1379..e66fc2a 100644 --- a/server/src/api/socket.js +++ b/server/src/api/socket.js @@ -22,6 +22,6 @@ export default (server) => { console.log('Disconnected from the client.') }) - socket.send('Hello from server!') + socket.send(`${container.id}\n`) }) } diff --git a/server/src/utils/docker.js b/server/src/utils/docker.js index 1095d38..d6b56ac 100644 --- a/server/src/utils/docker.js +++ b/server/src/utils/docker.js @@ -13,6 +13,20 @@ const containerOptions = { StdinOnce: false, } +export async function createContainer() { + const container = await engine.createContainer({ + ...containerOptions, + }) + await container.start() + return container +} + +export async function getContainer(id) { + const container = await engine.getContainer(id) + await container.start() + return container +} + export async function getOrCreateContainer(name) { try { const container = engine.getContainer(name) @@ -31,12 +45,20 @@ export async function getOrCreateContainer(name) { } } -export function attachContainer(container) { +export async function attachContainer(container) { // Create an exec instance with bash shell - return container.attach({ - stream: true, - stdin: true, - stdout: true, - stderr: true, + const exec = await container.exec({ + AttachStdin: true, + AttachStdout: true, + AttachStderr: true, + Cmd: ['/bin/bash'], + Tty: true, }) + + const execOutput = await exec.start({ + Detach: false, + Tty: true, + }) + + return execOutput.socket } From 95fc25d0add0dab8f36bbca83be8e0b461b3e197 Mon Sep 17 00:00:00 2001 From: wancat Date: Mon, 24 Jul 2023 12:18:01 +0800 Subject: [PATCH 2/3] feat: connect to different container by sessions Based on the file summaries provided, the best label for this commit would be "feat". This is because the commit introduces several new features to the codebase, such as adding a new ESLint rule, adding a new property to a function, adding authentication middleware, adding a query parameter, and adding a new function to handle user authentication.: update authentication and session handling - Add `"camelcase"` rule to ESLint configuration - Add `containerId` property to the `newSession` object in the `createSession` function - Add authentication middleware to the socket.io connection - Add a query parameter `session_id` to the socket.io connection in `client.js` - Add `defaultUser` function to handle user authentication - Update the `authMiddleware` function to use the `defaultUser` function - Add `defaultUser` function to handle user authentication in `auth.js` - Update `getOrCreateContainer` function to use the `id` parameter instead of `name` parameter --- .eslintrc.js | 1 + .../src/api/controllers/sessionController.js | 1 + server/src/api/socket.js | 28 ++++++++++++++++++- server/src/client.js | 9 +++++- server/src/middleware/auth.js | 12 ++------ server/src/utils/auth.js | 14 ++++++++++ server/src/utils/docker.js | 7 +++-- 7 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 server/src/utils/auth.js diff --git a/.eslintrc.js b/.eslintrc.js index e36019a..ebfa30a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -19,5 +19,6 @@ module.exports = { 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'import/extensions': 'off', + camelcase: ['error', { properties: 'never', ignoreDestructuring: true }], }, } diff --git a/server/src/api/controllers/sessionController.js b/server/src/api/controllers/sessionController.js index 574e50d..19d431d 100644 --- a/server/src/api/controllers/sessionController.js +++ b/server/src/api/controllers/sessionController.js @@ -25,6 +25,7 @@ export async function createSession(req, res) { const newSession = new Session({ user: req.user, quest, + containerId: `quest-${quest.id}-${req.user.username}-${Date.now()}`, }) try { diff --git a/server/src/api/socket.js b/server/src/api/socket.js index e66fc2a..5f08973 100644 --- a/server/src/api/socket.js +++ b/server/src/api/socket.js @@ -1,12 +1,38 @@ import { Server } from 'socket.io' import { getOrCreateContainer, attachContainer } from '../utils/docker.js' +import Session from '../models/session.js' +import { defaultUser } from '../utils/auth.js' export default (server) => { const io = new Server(server) + io.use(async (socket, next) => { + console.log('Authenticating...') + try { + const user = await defaultUser() + // eslint-disable-next-line no-param-reassign + socket.user = user + next() + } catch (err) { + console.error(err) + next(err) + } + }) + io.on('connection', async (socket) => { console.log('Connected to the client.') - const container = await getOrCreateContainer('odyssey-test') + const session = await Session.findOne({ + _id: socket.handshake.query.session_id, + user: socket.user, + }) + + if (!session) { + socket.send('Session not found.') + socket.disconnect() + return + } + + const container = await getOrCreateContainer(session.containerId) const stream = await attachContainer(container) stream.on('data', (chunk) => { diff --git a/server/src/client.js b/server/src/client.js index cdbf7b8..40e16cd 100644 --- a/server/src/client.js +++ b/server/src/client.js @@ -5,7 +5,14 @@ stdin.setRawMode(true) stdin.resume() stdin.setEncoding('utf8') -const socket = io('ws://localhost:3000') +const sessionId = process.argv[2] +console.log(`Session ID: ${sessionId}`) + +const socket = io('ws://localhost:3000', { + query: { + session_id: sessionId, + }, +}) socket.on('open', function open() { console.log('Connected to the server.') diff --git a/server/src/middleware/auth.js b/server/src/middleware/auth.js index 43c8826..62bb190 100644 --- a/server/src/middleware/auth.js +++ b/server/src/middleware/auth.js @@ -1,17 +1,9 @@ /* eslint-disable import/prefer-default-export */ -import User from '../models/user.js' +import { defaultUser } from '../utils/auth.js' export async function authMiddleware(req, res, next) { try { - let user = await User.findOne({ username: 'defaultUser' }) - if (!user) { - user = new User({ - username: 'defaultUser', - email: 'john@example.com', - }) - await user.save() - } - req.user = user + req.user = await defaultUser() next() } catch (err) { res.status(500).json({ message: err.message }) diff --git a/server/src/utils/auth.js b/server/src/utils/auth.js new file mode 100644 index 0000000..e33cf5f --- /dev/null +++ b/server/src/utils/auth.js @@ -0,0 +1,14 @@ +/* eslint-disable import/prefer-default-export */ +import User from '../models/user.js' + +export async function defaultUser() { + let user = await User.findOne({ username: 'defaultUser' }) + if (!user) { + user = new User({ + username: 'defaultUser', + email: 'jackson@example.com', + }) + await user.save() + } + return user +} diff --git a/server/src/utils/docker.js b/server/src/utils/docker.js index d6b56ac..a78b738 100644 --- a/server/src/utils/docker.js +++ b/server/src/utils/docker.js @@ -27,9 +27,10 @@ export async function getContainer(id) { return container } -export async function getOrCreateContainer(name) { +export async function getOrCreateContainer(id) { + console.log(`Getting container: ${id}`) try { - const container = engine.getContainer(name) + const container = engine.getContainer(id) if (!(await container.inspect()).State.Running) { await container.start() } @@ -37,7 +38,7 @@ export async function getOrCreateContainer(name) { } catch (error) { const container = await engine.createContainer({ ...containerOptions, - name, + name: id, }) await container.start() console.log(container.id) From 5fd611ab51b09d69375edbafabcabb4af7525800 Mon Sep 17 00:00:00 2001 From: wancat Date: Mon, 24 Jul 2023 15:06:48 +0800 Subject: [PATCH 3/3] docs: improve comments and remove unnecessary lines - Add a comment about creating a session with a POST request to `/api/v1/sessions` - Remove the line mentioning `yarn cli` command - Add a comment about using the `_id` field in the response - Remove the example usage of `yarn cli` Signed-off-by: wancat --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 21d4c9e..2b70dd9 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,22 @@ yarn app ## CLI terminal client -Open server first, then +Open server first, then create a session by `POST /api/v1/sessions` + +```bash +curl -X 'POST' \ + 'http://localhost:3000/api/v1/sessions' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "quest_id": "helloworld" +}' +``` + +Then use the `_id` field in response ``` -yarn cli +yarn cli [_id] +# example +yarn cli 64be226a39c0043cd1cdf7c2 ```