nsolid-manager
Version:
A manager that sets up and runs N|Solid for you
216 lines (180 loc) • 6.21 kB
JavaScript
const hub = require('./hub')
const config = require('./config')()
const url = require('url')
const path = require('path')
const fs = require('fs')
const createRouter = require('routes')
const computeAppId = require('../compute-app-id')
module.exports = createServerRoutes
// TODO: refactor - this argument list is way too long
function respond (storagePath, storageDirectory, extension, res, params, cmd, cache) {
const processHub = cache.processToHub[params.id]
if (!processHub) return respondWithError(404, res, new Error('process not found'))
const c = hub.createStream(cmd, {
app: params.app,
id: params.id
}, processHub)
const time = Date.now()
const filename = generateFilename(params.app, params.id, time, extension)
c.pipe(fs.createWriteStream(path.join(storagePath, storageDirectory, filename)))
c.on('error', function handleProfileError (err) {
respondWithError(res, err)
})
c.on('end', function (code) {
const insert = {
time: time,
app: params.app,
id: params.id,
date: new Date(),
file: filename,
title: params.title,
pid: params.pid
}
cache.addFileResource(storageDirectory, insert)
res.setHeader('content-type', 'application/json')
res.end(JSON.stringify(insert) + '\n')
})
}
function generateFilename (appName, processId, time, extension) {
var appId = computeAppId(appName)
if (!appId) return null
return [appId, processId, time].join('-') + '.' + extension
}
function respondWithError (code, res, err) {
// TODO: proper error codes
res.writeHead(code, { 'content-type': 'application/json' })
res.end(JSON.stringify({
message: err.message,
code: err.code
}) + '\n')
}
function respondFileExists (res, file) {
fs.stat(file, function (e, r) {
if (e) {
res.writeHead(404)
} else {
res.writeHead(200, {
'content-length': r.size
})
}
res.end()
})
}
function createServerRoutes (storagePath, cache) {
var router = createRouter()
router.addRoute('/heapsnapshot', function createHeapSnapshot (req, res, match) {
var method = req.method.toLowerCase()
var parsedUrl = url.parse(req.url, true)
var params = parsedUrl.query
var time = params.time || Date.now()
var filename = generateFilename(
params.app,
params.id,
time,
'heapsnapshot'
)
if (!filename) {
return respondWithError(400, res, new Error('could not compute filename'))
}
var file = path.resolve(storagePath, path.join('snapshots', filename))
if (method === 'head') {
respondFileExists(res, file)
} else if (method === 'get') {
var readStream = fs.createReadStream(file)
readStream.on('open', function downloadSnapshotOpen () {
res.setHeader('Content-Type', 'application/json')
res.setHeader('Content-Disposition', 'attachment; filename=' + filename)
readStream.pipe(res)
})
readStream.on('error', function downloadSnapshotError (error) {
respondWithError(404, res, error)
})
} else if (method === 'post') {
const processHub = cache.processToHub[params.id]
if (!processHub) return respondWithError(404, res, new Error('process not found'))
const c = hub.createStream('snapshot', params, processHub, config)
c.pipe(fs.createWriteStream(file))
c.on('error', function handleSnapshotError (err) {
respondWithError(500, res, err)
})
c.on('end', function snapshotStreamEnd () {
const insert = {
time: time,
app: params.app,
id: params.id,
date: new Date(),
file: filename,
title: params.title,
pid: params.pid
}
cache.addFileResource('snapshots', insert)
res.setHeader('content-type', 'application/json')
res.end(JSON.stringify(insert) + '\n')
})
} else {
res.end()
}
})
router.addRoute('/cpuprofile', function createProfile (req, res, match, db) {
var method = req.method.toLowerCase()
var parsedUrl = url.parse(req.url, true)
var params = parsedUrl.query
var time = params.time || Date.now()
var filename = generateFilename(
params.app,
params.id,
time,
'cpuprofile'
)
if (!filename) {
res.writeHead(400)
return res.end()
}
var file = path.resolve(storagePath, path.join('profiles', filename))
if (method === 'head') {
respondFileExists(res, file)
} else if (method === 'get') {
// e.g.: http://localhost:3000/applications/default-nsolid-scenario/processes/1062671c412debb5fdd538e08a333bd1f51dd152/profile?time=1438049368666
var readStream = fs.createReadStream(file)
readStream.on('open', function () {
res.setHeader('Content-Type', 'application/json')
res.setHeader('Content-Disposition', 'attachment; filename=' + filename)
readStream.pipe(res)
})
readStream.on('error', function (error) {
if (error.code === 'ENOENT') {
res.writeHead(404)
} else {
res.writeHead(500)
}
res.end(error.toString())
})
} else if (method === 'post') {
var duration = 5
if (params.duration) {
var intermediary = parseInt(params.duration, 10)
if (!isNaN(intermediary)) {
duration = intermediary
}
}
const processHub = cache.processToHub[params.id]
if (!processHub) return respondWithError(404, res, new Error('process not found'))
// curl -X POST :3000/applications/default-nsolid-scenario/processes/1062671c412debb5fdd538e08a333bd1f51dd152/profile
const s = hub.createStream('profile_start', {
app: params.app,
id: params.id
}, processHub)
s.on('error', function profileStartError (err) {
if (err) return respondWithError(500, res, err)
})
s.on('end', function profileStarted () {
setTimeout(function () {
respond(storagePath, 'profiles', 'cpuprofile', res, params, 'profile_stop', cache)
}, duration * 1000)
})
} else {
res.end()
}
})
return router
}