UNPKG

nsolid-manager

Version:

A manager that sets up and runs N|Solid for you

216 lines (180 loc) 6.21 kB
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 }