You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
3.8 KiB
JavaScript
150 lines
3.8 KiB
JavaScript
import express from 'express'
|
|
import { WebSocketServer } from 'ws'
|
|
import { createContainerPty } from './docker.js'
|
|
import { getContainerPath, runCommand } from './utils.js'
|
|
import path from 'path'
|
|
|
|
import fs from 'fs/promises'
|
|
|
|
const app = express()
|
|
|
|
app.use(express.json({ strict: false }))
|
|
|
|
// TODO: Convert to spawn + websocket
|
|
app.get('/api/container/:uuid([a-zA-Z0-9-]+)/exec/shell', async (req, res) => {
|
|
const uuid = req.params.uuid
|
|
|
|
/** @type {string} */
|
|
const command = JSON.parse(req.query.command)
|
|
|
|
try {
|
|
const output = await runCommand('docker', ['exec', uuid, '/bin/sh', '-c', command])
|
|
res.json(output)
|
|
} catch (e) {
|
|
res.json({ error: e.toString() })
|
|
}
|
|
})
|
|
|
|
// app.get('/api/container/:uuid([a-zA-Z0-9-]+)/exec/ls/*', async (req, res) => {
|
|
// const uuid = req.params.uuid
|
|
// const p = path.normalize(req.params[0])
|
|
|
|
// try {
|
|
// const files = await runCommand('/bin/ls', [path.join(getContainerPath('phc', uuid), p)])
|
|
|
|
// res.json(files.trim().split('\n'))
|
|
// } catch (e) {
|
|
// res.json({ error: e.toString() })
|
|
// }
|
|
// })
|
|
|
|
app.get('/api/container/:uuid([a-zA-Z0-9-]+)/exec/ls/*', async (req, res) => {
|
|
const uuid = req.params.uuid
|
|
const p = path.normalize(req.params[0])
|
|
|
|
try {
|
|
const dirPath = path.join(getContainerPath('phc', uuid), p)
|
|
const fileList = await fs.readdir(dirPath)
|
|
|
|
const result = await Promise.all(
|
|
fileList.map(async name => {
|
|
const fullPath = path.join(dirPath, name)
|
|
const stats = await fs.lstat(fullPath)
|
|
|
|
return {
|
|
type: stats.isDirectory() ? 'folder' : 'file',
|
|
name,
|
|
}
|
|
})
|
|
)
|
|
|
|
result.sort((e1, e2) => e2.type.localeCompare(e1.type))
|
|
|
|
res.json(result)
|
|
} catch (e) {
|
|
res.json({ error: e.toString() })
|
|
}
|
|
})
|
|
|
|
app.get('/api/container/:uuid([a-zA-Z0-9-]+)/fs/*', async (req, res) => {
|
|
const uuid = req.params.uuid
|
|
const p = path.normalize(req.params[0])
|
|
|
|
console.log('Getting', p)
|
|
|
|
try {
|
|
const content = await fs.readFile(path.join(getContainerPath('phc', uuid), p), 'utf8')
|
|
res.json(content)
|
|
} catch (e) {
|
|
res.json({ error: e.toString() })
|
|
}
|
|
})
|
|
|
|
app.put('/api/container/:uuid([a-zA-Z0-9-]+)/fs/*', async (req, res) => {
|
|
const uuid = req.params.uuid
|
|
const p = path.normalize(req.params[0])
|
|
|
|
const content = req.body
|
|
console.log(content)
|
|
|
|
try {
|
|
// await fs.writeFile(path.join(getContainerPath('phc', uuid), p), content)
|
|
|
|
await runCommand('docker', ['exec', '-i', uuid, '/usr/bin/tee', `/project/${p}`], {
|
|
stdin: content,
|
|
})
|
|
|
|
res.json('ok')
|
|
} catch (e) {
|
|
res.json({ error: e.toString() })
|
|
}
|
|
})
|
|
|
|
const server = app.listen(5432, () => {
|
|
console.log('Starting API server on :5432...')
|
|
})
|
|
|
|
const wss = new WebSocketServer({ server })
|
|
|
|
wss.on('connection', async (ws, req) => {
|
|
const tag = req.url.split('/').at(-2)
|
|
|
|
console.log(`Client connected to "${tag}"`)
|
|
|
|
const container = await createContainerPty(tag, {
|
|
onData(data) {
|
|
ws.send(
|
|
JSON.stringify({
|
|
type: 'pty',
|
|
data,
|
|
})
|
|
)
|
|
},
|
|
onExit(e) {
|
|
ws.send(
|
|
JSON.stringify({
|
|
type: 'destroyed',
|
|
...e,
|
|
})
|
|
)
|
|
ws.close()
|
|
},
|
|
})
|
|
|
|
ws.send(
|
|
JSON.stringify({
|
|
type: 'created',
|
|
id: container.id,
|
|
})
|
|
)
|
|
|
|
ws.on('message', data => {
|
|
container.pty.write(data)
|
|
})
|
|
|
|
ws.on('close', () => {
|
|
container.pty.kill()
|
|
console.log(`Client disconnected`)
|
|
})
|
|
})
|