mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-05 19:20:12 +08:00
refactor: container
This commit is contained in:
1 parent
075e21fb89
commit
64215d3ef1
7 files changed
+128
-24
No files matched your search
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
"app": "yarn workspace app dev",
|
"app": "yarn workspace app dev",
|
||||||
"app:local": "yarn workspace app dev:local",
|
"app:local": "yarn workspace app dev:local",
|
||||||
"build": "yarn workspaces foreach -Apt run build",
|
"build": "yarn workspaces foreach -Apt run build",
|
||||||
"dev": "yarn workspaces foreach -Api --include '{server,app}' run watch",
|
"dev": "yarn workspaces foreach -Api --include '{server,app}' run dev",
|
||||||
"server": "yarn workspace server dev",
|
"server": "yarn workspace server dev",
|
||||||
"cli": "yarn workspace client start",
|
"cli": "yarn workspace client start",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import mongoose from 'mongoose'
|
import mongoose from 'mongoose'
|
||||||
|
|
||||||
export { User } from './user.js'
|
export { User, IUser } from './user.js'
|
||||||
export { Quest, IQuest } from './quest.js'
|
export { Quest, IQuest } from './quest.js'
|
||||||
export { Session } from './session.js'
|
export { Session, ISession } from './session.js'
|
||||||
export { Command, ICommand } from './command.js'
|
export { Command, ICommand } from './command.js'
|
||||||
export { UserProfile } from './userProfile.js'
|
export { UserProfile, IUserProfile } from './userProfile.js'
|
||||||
|
|
||||||
export default async function connectDB(uri: string) {
|
export default async function connectDB(uri: string) {
|
||||||
const db = await mongoose.connect(uri)
|
const db = await mongoose.connect(uri)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const taskSchema = new Schema<ITask>({
|
|||||||
export interface ISession {
|
export interface ISession {
|
||||||
user: Types.ObjectId
|
user: Types.ObjectId
|
||||||
quest: string
|
quest: string
|
||||||
containerId: string
|
containerId: string | null
|
||||||
status: string
|
status: string
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
|
|||||||
@@ -45,9 +45,11 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bcrypt": "^5.0.2",
|
"@types/bcrypt": "^5.0.2",
|
||||||
|
"@types/dockerode": "^3.3.23",
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/express-session": "^1.17.10",
|
"@types/express-session": "^1.17.10",
|
||||||
"@types/jsonwebtoken": "^9.0.5",
|
"@types/jsonwebtoken": "^9.0.5",
|
||||||
|
"@types/node-schedule": "^2.1.6",
|
||||||
"@types/passport": "^1.0.16",
|
"@types/passport": "^1.0.16",
|
||||||
"@types/passport-github2": "^1.2.9",
|
"@types/passport-github2": "^1.2.9",
|
||||||
"@types/passport-jwt": "^4.0.1",
|
"@types/passport-jwt": "^4.0.1",
|
||||||
|
|||||||
@@ -14,9 +14,12 @@ const containerOptions = {
|
|||||||
HostConfig: {
|
HostConfig: {
|
||||||
NetworkMode: config.docker.network,
|
NetworkMode: config.docker.network,
|
||||||
},
|
},
|
||||||
}
|
} as Docker.ContainerCreateOptions
|
||||||
|
|
||||||
export function createContainer(name, questId) {
|
export function createContainer(
|
||||||
|
name: string,
|
||||||
|
questId: string
|
||||||
|
): Promise<Docker.Container> {
|
||||||
const option = {
|
const option = {
|
||||||
...containerOptions,
|
...containerOptions,
|
||||||
name,
|
name,
|
||||||
@@ -25,7 +28,7 @@ export function createContainer(name, questId) {
|
|||||||
const { hostPwd, mountQuest } = config.docker
|
const { hostPwd, mountQuest } = config.docker
|
||||||
if (!config.isProduction && hostPwd && mountQuest === questId) {
|
if (!config.isProduction && hostPwd && mountQuest === questId) {
|
||||||
logger.info('Mounting quest folder', mountQuest)
|
logger.info('Mounting quest folder', mountQuest)
|
||||||
option.HostConfig.Binds = [
|
option.HostConfig!.Binds = [
|
||||||
`${hostPwd}/quests/${mountQuest}/home:/home/commander`,
|
`${hostPwd}/quests/${mountQuest}/home:/home/commander`,
|
||||||
`${hostPwd}/packages/container:/usr/local/lib/container`,
|
`${hostPwd}/packages/container:/usr/local/lib/container`,
|
||||||
]
|
]
|
||||||
@@ -33,7 +36,9 @@ export function createContainer(name, questId) {
|
|||||||
return engine.createContainer(option)
|
return engine.createContainer(option)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAndStartContainer(id) {
|
export async function getAndStartContainer(
|
||||||
|
id: string
|
||||||
|
): Promise<Docker.Container> {
|
||||||
logger.debug(`Getting container: ${id}`)
|
logger.debug(`Getting container: ${id}`)
|
||||||
const container = engine.getContainer(id)
|
const container = engine.getContainer(id)
|
||||||
if (!container) {
|
if (!container) {
|
||||||
@@ -45,7 +50,10 @@ export async function getAndStartContainer(id) {
|
|||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function attachContainer(container, { token }) {
|
export async function attachContainer(
|
||||||
|
container: Docker.Container,
|
||||||
|
{ token }: { token: string }
|
||||||
|
) {
|
||||||
const exec = await container.exec({
|
const exec = await container.exec({
|
||||||
AttachStdin: true,
|
AttachStdin: true,
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
@@ -67,7 +75,7 @@ export async function attachContainer(container, { token }) {
|
|||||||
return execOutput
|
return execOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteContainer(id) {
|
export async function deleteContainer(id: string) {
|
||||||
const container = engine.getContainer(id)
|
const container = engine.getContainer(id)
|
||||||
if (!container) {
|
if (!container) {
|
||||||
return
|
return
|
||||||
@@ -80,8 +88,8 @@ export async function deleteContainer(id) {
|
|||||||
await container.remove()
|
await container.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseJSONOutput(data) {
|
function parseJSONOutput(data: string) {
|
||||||
const { stream, error } = JSON.parse(data.toString())
|
const { stream, error } = JSON.parse(data)
|
||||||
if (stream) {
|
if (stream) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(stream)
|
console.log(stream)
|
||||||
@@ -91,7 +99,7 @@ function parseJSONOutput(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildQuestImage(questPath, questId) {
|
export function buildQuestImage(questPath: string, questId: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
engine.buildImage(
|
engine.buildImage(
|
||||||
{
|
{
|
||||||
@@ -114,9 +122,9 @@ export function buildQuestImage(questPath, questId) {
|
|||||||
data
|
data
|
||||||
.toString()
|
.toString()
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.map((line) => line.trim())
|
.map((line: string) => line.trim())
|
||||||
.filter((line) => line !== '')
|
.filter((line: string) => line !== '')
|
||||||
.forEach((line) => {
|
.forEach((line: string) => {
|
||||||
parseJSONOutput(line)
|
parseJSONOutput(line)
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1,18 +1,30 @@
|
|||||||
import schedule from 'node-schedule'
|
import schedule from 'node-schedule'
|
||||||
import { Session } from '@linux-odyssey/models'
|
import { Session } from '@linux-odyssey/models'
|
||||||
|
import type { ISession } from '@linux-odyssey/models'
|
||||||
|
import type { HydratedDocument } from 'mongoose'
|
||||||
import config from '../config.js'
|
import config from '../config.js'
|
||||||
import { deleteContainer } from './docker.js'
|
import { deleteContainer } from './docker.js'
|
||||||
import logger from '../utils/logger.js'
|
import logger from '../utils/logger.js'
|
||||||
|
|
||||||
async function disableSession(session) {
|
async function disableSession(session: HydratedDocument<ISession>) {
|
||||||
|
if (!session.containerId) {
|
||||||
|
logger.warn(`Deleting session ${session._id} has no containerId`)
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await deleteContainer(session.containerId)
|
await deleteContainer(session.containerId)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// If the container doesn't exist, we can ignore the error
|
// Perform runtime check to safely access statusCode
|
||||||
if (err.statusCode !== 404) {
|
if (typeof err === 'object' && err !== null && 'statusCode' in err) {
|
||||||
throw new Error(
|
const error = err as { statusCode: number }
|
||||||
`Failed to delete container ${session.containerId} for session ${session._id}`
|
if (error.statusCode !== 404) {
|
||||||
)
|
throw new Error(
|
||||||
|
`Failed to delete container ${session.containerId} for session ${session._id}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle the case where err is not the expected type
|
||||||
|
logger.error(`An unexpected error occurred: ${err}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (session.status === 'active') {
|
if (session.status === 'active') {
|
||||||
@@ -1110,10 +1110,19 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@linux-odyssey/models@npm:*, @linux-odyssey/models@workspace:packages/models":
|
"@linux-odyssey/game@workspace:packages/game":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@linux-odyssey/game@workspace:packages/game"
|
||||||
|
dependencies:
|
||||||
|
"@linux-odyssey/models": "workspace:^"
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
|
"@linux-odyssey/models@npm:*, @linux-odyssey/models@workspace:^, @linux-odyssey/models@workspace:packages/models":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@linux-odyssey/models@workspace:packages/models"
|
resolution: "@linux-odyssey/models@workspace:packages/models"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@types/mongoose": "npm:^5.11.97"
|
||||||
mongoose: "npm:^8.0.3"
|
mongoose: "npm:^8.0.3"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
@@ -1395,6 +1404,26 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/docker-modem@npm:*":
|
||||||
|
version: 3.0.6
|
||||||
|
resolution: "@types/docker-modem@npm:3.0.6"
|
||||||
|
dependencies:
|
||||||
|
"@types/node": "npm:*"
|
||||||
|
"@types/ssh2": "npm:*"
|
||||||
|
checksum: 10c0/d3ffd273148bc883ff9b1a972b1f84c1add6d9a197d2f4fc9774db4c814f39c2e51cc649385b55d781c790c16fb0bf9c1f4c62499bd0f372a4b920190919445d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/dockerode@npm:^3.3.23":
|
||||||
|
version: 3.3.23
|
||||||
|
resolution: "@types/dockerode@npm:3.3.23"
|
||||||
|
dependencies:
|
||||||
|
"@types/docker-modem": "npm:*"
|
||||||
|
"@types/node": "npm:*"
|
||||||
|
checksum: 10c0/b6bdb2851487ac7168d2a790ef35b50f0521cbf01e636feaca8f7192fe9c4c687c22f71c56767f41b25ceb87d60ebbc052c1e28c6f7d6cc7a69327050569c863
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/express-serve-static-core@npm:^4.17.33":
|
"@types/express-serve-static-core@npm:^4.17.33":
|
||||||
version: 4.17.43
|
version: 4.17.43
|
||||||
resolution: "@types/express-serve-static-core@npm:4.17.43"
|
resolution: "@types/express-serve-static-core@npm:4.17.43"
|
||||||
@@ -1516,6 +1545,24 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/mongoose@npm:^5.11.97":
|
||||||
|
version: 5.11.97
|
||||||
|
resolution: "@types/mongoose@npm:5.11.97"
|
||||||
|
dependencies:
|
||||||
|
mongoose: "npm:*"
|
||||||
|
checksum: 10c0/333e692a39734948db700c76f25c7b088f46cb88ba940b80467313acf29752823ff9ed2870045c34e00559c38a4a3b5136ae6634da6dbe56c160a16a50e1dea0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/node-schedule@npm:^2.1.6":
|
||||||
|
version: 2.1.6
|
||||||
|
resolution: "@types/node-schedule@npm:2.1.6"
|
||||||
|
dependencies:
|
||||||
|
"@types/node": "npm:*"
|
||||||
|
checksum: 10c0/5b8f810abf1738f4114c771434ebd17b6ec4f5e29d9f4ca4085b7b5d016f88dd6d99c7fa5c9e0d8583a52781e7ab579f34adfd6927071aa03168b44d9d75e7fd
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:*, @types/node@npm:>=10.0.0, @types/node@npm:^20.10.4":
|
"@types/node@npm:*, @types/node@npm:>=10.0.0, @types/node@npm:^20.10.4":
|
||||||
version: 20.11.16
|
version: 20.11.16
|
||||||
resolution: "@types/node@npm:20.11.16"
|
resolution: "@types/node@npm:20.11.16"
|
||||||
@@ -1525,6 +1572,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/node@npm:^18.11.18":
|
||||||
|
version: 18.19.17
|
||||||
|
resolution: "@types/node@npm:18.19.17"
|
||||||
|
dependencies:
|
||||||
|
undici-types: "npm:~5.26.4"
|
||||||
|
checksum: 10c0/ac2e4910d5f2bb92cb2623f6d4d4d665a39cf1d425993347e6c3756c70a4def21a47241b86f49e1e4f441529753527bbd9be5f08f29fdac38c64035a26b847c7
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/oauth@npm:*":
|
"@types/oauth@npm:*":
|
||||||
version: 0.9.4
|
version: 0.9.4
|
||||||
resolution: "@types/oauth@npm:0.9.4"
|
resolution: "@types/oauth@npm:0.9.4"
|
||||||
@@ -1652,6 +1708,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/ssh2@npm:*":
|
||||||
|
version: 1.11.19
|
||||||
|
resolution: "@types/ssh2@npm:1.11.19"
|
||||||
|
dependencies:
|
||||||
|
"@types/node": "npm:^18.11.18"
|
||||||
|
checksum: 10c0/d1a6f8bff3602ea40be0f9b41f2c80bdd8debbda412b50cda5d7b973ef3921ede60123ea0c48c9e202d96d71c7dc05c9019b5736e8b2ddc6c457c557f602453e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/stack-utils@npm:^2.0.0":
|
"@types/stack-utils@npm:^2.0.0":
|
||||||
version: 2.0.3
|
version: 2.0.3
|
||||||
resolution: "@types/stack-utils@npm:2.0.3"
|
resolution: "@types/stack-utils@npm:2.0.3"
|
||||||
@@ -7178,6 +7243,21 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"mongoose@npm:*":
|
||||||
|
version: 8.1.3
|
||||||
|
resolution: "mongoose@npm:8.1.3"
|
||||||
|
dependencies:
|
||||||
|
bson: "npm:^6.2.0"
|
||||||
|
kareem: "npm:2.5.1"
|
||||||
|
mongodb: "npm:6.3.0"
|
||||||
|
mpath: "npm:0.9.0"
|
||||||
|
mquery: "npm:5.0.0"
|
||||||
|
ms: "npm:2.1.3"
|
||||||
|
sift: "npm:16.0.1"
|
||||||
|
checksum: 10c0/68cf62251b245fb3f9867f0f66895b751f688dcda4c3b9b9016754ad6d78428535d7a4094f013e6e4545158ed2d766aea94aff4478b7a2e3876cefe79a59447c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"mongoose@npm:^8.0.3":
|
"mongoose@npm:^8.0.3":
|
||||||
version: 8.1.1
|
version: 8.1.1
|
||||||
resolution: "mongoose@npm:8.1.1"
|
resolution: "mongoose@npm:8.1.1"
|
||||||
@@ -8530,9 +8610,11 @@ __metadata:
|
|||||||
"@linux-odyssey/models": "npm:*"
|
"@linux-odyssey/models": "npm:*"
|
||||||
"@linux-odyssey/utils": "npm:*"
|
"@linux-odyssey/utils": "npm:*"
|
||||||
"@types/bcrypt": "npm:^5.0.2"
|
"@types/bcrypt": "npm:^5.0.2"
|
||||||
|
"@types/dockerode": "npm:^3.3.23"
|
||||||
"@types/express": "npm:^4.17.21"
|
"@types/express": "npm:^4.17.21"
|
||||||
"@types/express-session": "npm:^1.17.10"
|
"@types/express-session": "npm:^1.17.10"
|
||||||
"@types/jsonwebtoken": "npm:^9.0.5"
|
"@types/jsonwebtoken": "npm:^9.0.5"
|
||||||
|
"@types/node-schedule": "npm:^2.1.6"
|
||||||
"@types/passport": "npm:^1.0.16"
|
"@types/passport": "npm:^1.0.16"
|
||||||
"@types/passport-github2": "npm:^1.2.9"
|
"@types/passport-github2": "npm:^1.2.9"
|
||||||
"@types/passport-jwt": "npm:^4.0.1"
|
"@types/passport-jwt": "npm:^4.0.1"
|
||||||
|
|||||||
Reference in new issue
Block a user