const http = require('http'); const url = require('url'); const util = require('util'); const ProjectionCommandFailedError = require('../errors/projectionCommandFailedError'); const HTTP_OK = 200; const HTTP_CREATED = 201; function safeParseJson(json) { try { return JSON.parse(json); } catch(e) { return null; } } function ProjectionsClient(log, operationTimeout) { this._log = log; this._operationTimeout = operationTimeout; } ProjectionsClient.prototype.enable = function(httpEndPoint, name, userCredentials) { return this.sendPost(httpEndPoint + '/projection/' + name + '/command/enable', '', userCredentials, HTTP_OK); }; ProjectionsClient.prototype.disable = function(httpEndPoint, name, userCredentials) { return this.sendPost(httpEndPoint + '/projection/' + name + '/command/disable', '', userCredentials, HTTP_OK); }; ProjectionsClient.prototype.abort = function(httpEndPoint, name, userCredentials) { return this.sendPost(httpEndPoint + '/projection/' + name + '/command/abort', '', userCredentials, HTTP_OK); }; ProjectionsClient.prototype.createOneTime = function(httpEndPoint, query, userCredentials) { return this.sendPost(httpEndPoint + '/projections/onetime?type=JS', query, userCredentials, HTTP_CREATED); }; ProjectionsClient.prototype.createTransient = function(httpEndPoint, name, query, userCredentials) { return this.sendPost(httpEndPoint + '/projections/transient?name=' + name + '&type=JS', query, userCredentials, HTTP_CREATED); }; ProjectionsClient.prototype.createContinuous = function(httpEndPoint, name, query, trackEmittedStreams, userCredentials) { return this.sendPost(httpEndPoint + '/projections/continuous?name=' + name + '&type=JS&emit=1&trackemittedstreams=' + trackEmittedStreams, query, userCredentials, HTTP_CREATED); }; ProjectionsClient.prototype.listAll = function(httpEndPoint, userCredentials) { return this.sendGet(httpEndPoint + '/projections/any', userCredentials, HTTP_OK) .then(function (json) { var r = safeParseJson(json); if (r && r.projections) return r.projections; return null; }); }; ProjectionsClient.prototype.listOneTime = function(httpEndPoint, userCredentials) { return this.sendGet(httpEndPoint + '/projections/onetime', userCredentials, HTTP_OK) .then(function (json) { var r = safeParseJson(json); if (r && r.projections) return r.projections; return null; }); }; ProjectionsClient.prototype.listContinuous = function(httpEndPoint, userCredentials) { return this.sendGet(httpEndPoint + '/projections/continuous', userCredentials, HTTP_OK) .then(function (json) { var r = safeParseJson(json); if (r && r.projections) return r.projections; return null; }); }; ProjectionsClient.prototype.getStatus = function(httpEndPoint, name, userCredentials) { return this.sendGet(httpEndPoint + '/projection/' + name, userCredentials, HTTP_OK); }; ProjectionsClient.prototype.getState = function(httpEndPoint, name, userCredentials) { return this.sendGet(httpEndPoint + '/projection/' + name + '/state', userCredentials, HTTP_OK); }; ProjectionsClient.prototype.getPartitionState = function(httpEndPoint, name, partitionId, userCredentials) { return this.sendGet(httpEndPoint + '/projection/' + name + '/state?partition=' + partitionId, userCredentials, HTTP_OK); }; ProjectionsClient.prototype.getResult = function(httpEndPoint, name, userCredentials) { return this.sendGet(httpEndPoint + '/projection/' + name + '/result', userCredentials, HTTP_OK); }; ProjectionsClient.prototype.getPartitionResult = function(httpEndPoint, name, partitionId, userCredentials) { return this.sendGet(httpEndPoint + '/projection/' + name + '/result?partition=' + partitionId, userCredentials, HTTP_OK); }; ProjectionsClient.prototype.getStatistics = function(httpEndPoint, name, userCredentials) { return this.sendGet(httpEndPoint + '/projection/' + name + '/statistics', userCredentials, HTTP_OK); }; ProjectionsClient.prototype.getQuery = function(httpEndPoint, name, userCredentials) { return this.sendGet(httpEndPoint + '/projection/' + name + '/query', userCredentials, HTTP_OK); }; ProjectionsClient.prototype.updateQuery = function(httpEndPoint, name, query, userCredentials) { return this.sendPut(httpEndPoint + '/projection/' + name + '/query?type=JS', query, userCredentials, HTTP_OK); }; ProjectionsClient.prototype.delete = function(httpEndPoint, name, deleteEmittedStreams, deleteStateStream, deleteCheckpointStream, userCredentials) { const stateStream = (deleteStateStream === undefined) ? false : deleteStateStream; const checkpointStream = (deleteCheckpointStream === undefined) ? false : deleteCheckpointStream; return this.sendDelete(httpEndPoint + '/projection/' + name + '?deleteStateStream=' + stateStream + '&deleteCheckpointStream' + checkpointStream + '&deleteEmittedStreams=' + deleteEmittedStreams, userCredentials, HTTP_OK); }; ProjectionsClient.prototype.request = function(method, _url, data, userCredentials, expectedCode) { const options = url.parse(_url); options.method = method; if (userCredentials) { options.auth = [userCredentials.username, userCredentials.password].join(':'); } var self = this; return new Promise(function (resolve, reject) { const timeout = setTimeout(function () { reject(new Error(util.format('Request timed out for %s on %s', method, _url))) }, self._operationTimeout); const req = http.request(options, function (res) { const hasExpectedCode = res.statusCode === expectedCode; var result = ''; res.setEncoding('utf8'); res.on('data', function (chunk) { result += chunk; }); res.on('end', function () { if (hasExpectedCode) { clearTimeout(timeout); resolve(result); } else { clearTimeout(timeout); reject(new ProjectionCommandFailedError( res.statusCode, util.format('Server returned %d (%s) for %s on %s', res.statusCode, res.statusMessage, method, _url) )); } }); }); req.on('error', reject); if (data) { req.setHeader('Content-Length', data.length); req.setHeader('Content-Type', 'application/json'); req.write(data); } req.end(); }); }; function voidResult() {} ProjectionsClient.prototype.sendGet = function(_url, userCredentials, expectedCode) { return this.request('GET', _url, null, userCredentials, expectedCode); }; ProjectionsClient.prototype.sendPost = function(_url, data, userCredentials, expectedCode) { return this.request('POST', _url, data, userCredentials, expectedCode) .then(voidResult); }; ProjectionsClient.prototype.sendPut = function(_url, data, userCredentials, expectedCode) { return this.request('PUT', _url, data, userCredentials, expectedCode) .then(voidResult); }; ProjectionsClient.prototype.sendDelete = function(_url, data, userCredentials, expectedCode) { return this.request('DELETE', _url, data, userCredentials, expectedCode) .then(voidResult); }; module.exports = ProjectionsClient;