feat: mount quest

This commit is contained in:
Justin Lin committed 2024-10-10 17:21:38 +08:00
1 parent 9b4f50ebbd
commit 98f18627e5
4 files changed
+83 -26

No files matched your search

+60 -14
View File
@@ -5,9 +5,9 @@
## Requirements
- NodeJS
- NodeJS v20+
- Docker
- Yarn
- Yarn: v1.22
## Installation
@@ -17,25 +17,49 @@
## Development
Run mongoDB first:
### Project Structures
1. **app**: frontend
2. **server**: backend
3. **quests**: tutorials scripts for each quest
4. **packages**: other packages
1. **analytics**: admin dashboard to analyze collected data
2. **constants**: some shared config values for app and server
3. **container**: the script run in container to capture users' command
4. **file-graph**: the algorithm to construct and modify file graph, used in both app and server
5. **models**: definitions of MondoDB collections (data schema)
6. **utils**: other utility code shared between packages
7. **game (in the future)**: core logic of game playing, will be extracted from server
## Docker Setup
### Docker compose files explaination
1. **docker-compose.yml**: The one used for development. It sets up MongoDB and builds base quest image.
2. **docker-compose.prod.yml**: The one used for production deployment. It has a Nginx service, a backend, a database, an analytics service, and creates isolated networks for player containers.
3. **docker-compose.testing.yml**: Similar to production config, but sets up an one-time environment for end-to-end testing.
### Common Development Setup
This sets up a development database, and running development server for frontend and backend.
Pull the latest images:
docker compose pull
Start the containers:
docker compose up -d
The db will automatically restarts by Docker.
This will start the db. it will automatically restarts by Docker.
Build up dependencies:
Building quest images:
yarn build:deps
yarn build:quests
Run dev server (frontend, backend):
### Build Quest Images in Details
yarn dev
If you want to enable social login, you should have OAuth client token in a `.env` file:
### Build Quest Images
In each quest folder, there is a `game.yml` file, which is the quest definition. And a optional `Dockerfile` to overwrite the base image. If you want to include additional files, put them in a `home` folder. The files in `home` will **not** be copied to the image automatically, you have to copy them in the `Dockerfile`.
In each quest folder, there is a `game.yml` file, which is the quest definition. And a optional `Dockerfile` can overwrite the base image. If you want to include additional files, put them in a `home` folder. The files in `home` will **not** be copied to the image automatically, you have to copy them in the `Dockerfile`.
quests/
├── Dockerfile # Base image
@@ -60,6 +84,28 @@ To build all quests:
The base image is built with docker-compose, so you can use `docker compose build base` to rebuild it. Once you rebuild the base image, you have to rebuild all quests.
### Mounting Host Directory
To improve the development experience, we can mount the host directory to the container in the pattern:
/path/to/linux-odyssey/quests/${quest_id}/home:/home/commander
You can edit the files on your host, and the changes will be reflected in the container. This is disabled by default. To enable it, you can set the following environment variables:
MOUNT_QUEST=true
### Development
Build up dependencies:
yarn build:deps
Run dev server (frontend, backend):
yarn dev
If you want to enable social login, you should have OAuth client token in a `.env` file:
## Testing
Run Cypress locally, using the current development containers:
+2 -1
View File
@@ -56,5 +56,6 @@
"dependencies": {
"latest": "^0.2.0",
"typescript-eslint": "^7.4.0"
}
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
+14 -4
View File
@@ -1,5 +1,7 @@
import validator from 'validator'
import dotenv from 'dotenv'
import { fileURLToPath } from 'node:url'
import path from 'path'
import { get } from './utils/env.js'
// Import dotenv and load ../.env
@@ -43,8 +45,9 @@ function createConfig() {
db: get('MONGO_URL', 'mongodb://localhost:27017/odyssey-test'),
secret: get('SECRET_KEY', ''),
isProduction: process.env.NODE_ENV === 'production',
containerExpiry: get('EXPIRY', 1000 * 60 * 60),
sessionMaxAge: get('SESSION_MAX_AGE', 1000 * 60 * 60 * 24 * 7),
containerExpiry: Number(process.env.CONTAINER_EXPIRY ?? 60) * 1000 * 60,
sessionMaxAge:
Number(process.env.SESSION_MAX_AGE ?? 7 * 24) * 1000 * 60 * 60,
google: {
clientID: get('GOOGLE_CLIENT_ID', ''),
clientSecret: get('GOOGLE_CLIENT_SECRET', ''),
@@ -61,10 +64,11 @@ function createConfig() {
network: get('DOCKER_NETWORK', 'host'),
defaultImage: get('QUEST_IMAGE', 'linuxodyssey/quest-base'),
imagePrefix: get('DOCKER_PREFIX', 'linuxodyssey/quest-'),
mountQuest: get('MOUNT_QUEST', ''),
hostPwd: get('HOST_PWD', ''),
mountQuest: process.env.MOUNT_QUEST === 'true',
},
projectRoot: getProjectRoot(),
log: {
path: get('LOG_PATH', '../logs'),
},
@@ -76,6 +80,12 @@ function createConfig() {
}
}
function getProjectRoot(): string {
const filename = fileURLToPath(import.meta.url)
const root = path.join(path.dirname(filename), '..', '..')
return root
}
const config = createConfig()
export function getQuestImage(id: string): string {
+7 -7
View File
@@ -18,19 +18,19 @@ const containerOptions = {
export function createContainer(
name: string,
questId: string
imageId: string
): Promise<Docker.Container> {
const option = {
...containerOptions,
name,
Image: getQuestImage(questId),
Image: getQuestImage(imageId),
}
const { hostPwd, mountQuest } = config.docker
if (!config.isProduction && hostPwd && mountQuest === questId) {
logger.info('Mounting quest folder', mountQuest)
if (!config.isProduction && config.docker.mountQuest && imageId !== 'base') {
logger.info('Mounting quest folder', imageId)
option.HostConfig!.Binds = [
`${hostPwd}/quests/${mountQuest}/home:/home/commander`,
`${hostPwd}/packages/container:/usr/local/lib/container`,
`${config.projectRoot}/quests/${imageId}/home:/home/commander`,
`${config.projectRoot}/packages/container:/usr/local/lib/container`,
]
}
return engine.createContainer(option)