hugo-sandstorm/server.js

209 lines
4.9 KiB
JavaScript

import Nuxt from "nuxt"
import logger from "morgan"
import fs from 'fs'
import Express from "express"
import gitBackend from "git-http-backend"
import cloudcmd from "cloudcmd"
import io from 'socket.io'
const spawn = require("child_process").spawn
const app = new Express()
app.use(logger("dev"))
const server = require("http").createServer(app)
const host = process.env.HOST || "127.0.0.1"
const port = process.env.PORT || "8000"
app.set("port", port)
app.get("/publicId", (req, res) => {
// For those reusing getPublicId, keep in mind that the session ID from the
// headers isn't used to generate the address for a grain, only the grain's
// internal ID. Once you've generated it once, that's it.
//
// See https://github.com/sandstorm-io/sandstorm/blob/1a1f5650472904e137393af077a3d90f094cd888/shell/imports/server/hack-session.js#L334-L365
// for more information.
const sessionId = req.headers["x-sandstorm-session-id"]
let allData = ""
// TODO: needed until https://github.com/sandstorm-io/sandstorm/pull/3292 is merged
//
// If this app is running in demo mode, its data will be thrown away in an hour,
// and the public ID assigned to the grain will also go away, so it's still OK
// to keep this file around, even in a demo scenario.
const file = `/var/publicid`
const handleResult = () => {
const lines = allData.split("\n")
const publicId = lines[0]
const hostname = lines[1]
const domain = publicId+"."+hostname
const url = lines[2]
const isDemo = lines[3] == "true"
res.json({publicId, hostname, domain, url, isDemo})
}
try {
allData = fs.readFileSync(file, 'utf8').toString()
} catch (e) {
// file probably doesn't exist
}
const lines = allData.split("\n")
if (lines.length >= 4) {
handleResult()
} else {
const gpId = spawn('getPublicId', [sessionId])
allData = ""
gpId.stdout.on('data', (data) => {
fs.appendFileSync(file, data)
allData += data
})
gpId.on('error', (err) => {
return res.send(err)
})
gpId.on('close', (code) => {
if (code !== 0) {
return res.send(code)
}
handleResult()
})
}
})
app.use("/git", (req, res) => {
req.pipe(gitBackend(req.url, (err, service) => {
if(err)
return res.end(err+"\n")
res.setHeader("content-type", service.type)
console.log("cmd", service.cmd)
const ps = spawn(service.cmd, service.args.concat("/var/git"))
ps.stdout.pipe(service.createStream()).pipe(ps.stdin)
})).pipe(res)
})
const runCommand = (cmd, ...args) => {
return new Promise((resolve, reject) => {
const spawnCmd = spawn(cmd, args)
spawnCmd.stdout.on('data', (data) => {
console.log(data.toString())
})
spawnCmd.on('error', (err) => {
res.send(err)
reject(err)
})
spawnCmd.on('close', (code) => {
if (code === 0) {
resolve(true)
return true
} else {
reject(new Error(code))
}
})
})
}
app.get('/dirty', async (req, res) => {
const currentDir = process.cwd()
process.chdir('/var/git')
const spawnCmd = spawn('git', ['diff', '--exit-code'])
spawnCmd.on('close', (code) => {
res.json({ dirty: code !== 0 })
})
process.chdir(currentDir)
})
app.use('/commit', async (req, res) => {
const currentDir = process.cwd()
try {
process.chdir('/var/git')
await runCommand('git', 'add', '.')
await runCommand('git', 'commit', '-m', 'From admin')
process.chdir(currentDir)
await runCommand('/opt/app/post-receive')
res.json({ok: true})
} catch (e) {
res.send({error: e.msg})
} finally {
process.chdir(currentDir)
}
})
app.use('/reset-local', async (req, res) => {
const currentDir = process.cwd()
try {
process.chdir('/var/git')
await runCommand('git', 'reset', '--hard')
process.chdir(currentDir)
res.json({ok: true})
} catch (e) {
res.send({error: e.msg})
} finally {
process.chdir(currentDir)
}
})
const { createConfigManager, configPath } = cloudcmd
const socket = io.listen(server, { path: "/admin/socket.io"})
const cloudConfig = {
name: "Hugo admin",
root: "/var/git",
open: false,
prefix: "/admin",
console: false,
terminal: false,
oneFilePanel: true,
configDialog: false,
configAuth: false,
keysPanel: true,
}
const filePicker = {
data: { FilePicker: { key: 'key' } }
}
const cloudModules = { filePicker }
const configManager = createConfigManager({ configPath })
app.use("/admin", cloudcmd({
socket,
config: cloudConfig
}))
// Import and Set Nuxt.js options
let config = require("./nuxt.config.js")
config.dev = !(process.env.NODE_ENV === "production")
// Init Nuxt.js
const nuxt = new Nuxt(config)
app.use(nuxt.render)
// Build only in dev mode
if (config.dev) {
nuxt.build()
.catch((error) => {
console.error(error) // eslint-disable-line no-console
process.exit(1)
})
}
server.listen(port, host, () => console.log(`Server listening on ${host}:${port}`))