var express = require('express'); var bodyParser = require('body-parser'); var _ = require('lodash'); var di = require('di'); var DillerConfig = require('../DillerConfig'); var Diller = require('../Diller'); var DillerDb = require('../DillerDb'); var DillerDao = require('../DillerDao'); function DillerWeb(diller, db, config) { var log = config.log(); var calls = []; var app; function genericErrorHandler(res) { return function (data) { log.warn('fail', data); return res.status(500).json({message: 'fail', data: data}) } } function getDevices(req, res) { db().tx(function (pg) { var dao = new DillerDao(pg); return dao.devices(); }).then(function (devices) { res.json({devices: devices}); }, genericErrorHandler(res)); } function deviceResponse(data) { var device = data[0]; device.properties = data[1]; return {device: device}; } function getDevice(req, res) { db().tx(function (tx) { var deviceId = req.params.deviceId; var dao = new DillerDao(tx); return tx.batch([ dao.deviceById(deviceId), dao.devicePropertiesByDeviceId(deviceId)] ); }).then(function (data) { res.json(deviceResponse(data)); }, genericErrorHandler(res)); } function patchDevice(req, res) { db().tx(function (tx) { var deviceId = req.params.deviceId; var body = req.body; if (body.attribute == 'name') { diller.updateDeviceName(deviceId, body.value) .then(function () { var dao = new DillerDao(tx); return tx.batch([ dao.deviceById(deviceId), dao.devicePropertiesByDeviceId(deviceId)] ); }) .then(function (data) { res.json(deviceResponse(data)); }, genericErrorHandler(res)); } else { res.status(400).json({message: 'Required keys: "attribute" and "value".'}); } }).then(function (data) { var device = data[0]; device.properties = data[1]; res.json({device: device}); }, genericErrorHandler(res)); } function getValues(req, res) { db().tx(function (tx) { var propertyId = req.params.propertyId; var dao = new DillerDao(tx); return dao.valuesByPropertyId(propertyId, 10); }).then(function (values) { res.json({values: values}); }, function (err) { log.warn('fail', err); res.status(500).json({message: 'fail'}); }); } function getIndex(req, res) { var baseUrl = (req.headers['trygvis-prefix'] || '').replace(/\/$/, ''); res.render('index', {baseUrl: baseUrl + '/'}); } function init() { app = express(); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); var api = express.Router(); function addApi(name, method, path, callback) { api[method](path, callback); var layer = _.last(api.stack); var methodWithPayloads = { put: true, post: true, patch: true }; var keys = _.map(layer.keys, function (key) { return key.name; }); var hasPayload = methodWithPayloads[method]; if (hasPayload) { keys.push('payload'); } calls.push({ name: name, method: method, path: path, layer: layer, hasPayload: hasPayload, keys: keys }); } addApi('getDevices', 'get', '/device', getDevices); addApi('getDevice', 'get', '/device/:deviceId', getDevice); addApi('patchDevice', 'patch', '/device/:deviceId', patchDevice); addApi('getValues', 'get', '/property/:propertyId/values', getValues); var templates = express.Router(); templates.get('/', getIndex); app.set('views', 'web/templates'); app.set('view engine', 'jade'); app.set('view cache', false); app.use('/api', api); app.use('/', templates); app.use(express.static('web/static')); } function listen() { app.listen(config.httpPort); } function generateRpc() { var s = 'function DillerRpc($http, DillerConfig) {\n' + ' var baseUrl = DillerConfig.baseUrl;\n' + '\n'; s += _.map(calls, function (call) { var s = ' function ' + call.name + '(' + call.keys.join(', ') + ') {\n' + ' var req = {};\n' + ' req.method = \'' + call.method + '\';\n' + ' req.url = baseUrl + \'/api' + call.path + '\';\n'; s += _.map(call.layer.keys, function (key) { return ' req.url = req.url.replace(/:' + key.name + '/, ' + key.name + ');\n' }).join('\n'); if (call.hasPayload) { s += ' req.data = payload;\n'; } s += ' return $http(req);\n' + ' }\n'; return s; }).join('\n'); s += '\n'; s += ' return {\n'; s += _.map(calls, function (call) { return ' ' + call.name + ': ' + call.name }).join(',\n'); s += '\n'; s += ' };\n'; s += '}\n'; s += '\n'; s += 'DillerRpcResolve = {};\n'; s += _.map(calls, function (call) { var s = ''; var args = ['DillerRpc']; if (call.keys.length > 0) { args.push('$route'); } s += 'DillerRpcResolve.' + call.name + ' = function(' + args.join(', ') + ') {\n'; args = _.map(call.keys, function (key) { return '$route.current.params.' + key; }); s += ' return DillerRpc.' + call.name + '(' + args.join(', ') + ');\n'; s += '};\n'; return s; }).join(''); return s; } return { init: init, listen: listen, generateRpc: generateRpc } } di.annotate(DillerWeb, new di.Inject(Diller, DillerDb, DillerConfig)); module.exports = DillerWeb;