'use strict'; /** Node http/socket/promise wrapper. */ var http = require('http'); var debug = require('debug')('marionette-socket-host:request'); var Promise = require('promise'); var RETRIES = 60; var RETRY_TIMER = 5000; function PythonError(msg) { Error.call(msg); this.name = 'python_error'; } PythonError.prototype = { __proto__: Error.prototype }; module.exports = function request(socketPath, path, json, retry) { retry = retry || 0; var body = JSON.stringify(json || {}); return new Promise(function(accept, reject) { debug('issue request', socketPath, path, json); var req = http.request({ socketPath: socketPath, method: 'POST', path: path, headers: { 'Content-Length': Buffer.byteLength(body), 'Content-Type': 'application/json' } }); req.setTimeout(300 * 1000, function() { reject(new Error('Host request timeout exceeded.')); }); // The unix socket server may or may not be ready at this point so we retry // up to 5 times to ensure we are connected... req.once('error', function(err) { if (retry > RETRIES) { debug('At maximum retries...'); return reject(err); } debug('Error in socket request retrying...', err); setTimeout(function() { request(socketPath, path, json, retry + 1).then(accept, reject); }, RETRY_TIMER); }); // request sender.... req.write(body); req.on('abort', function() { debug('Request', retry, 'aborted.'); }); // response handler... req.on('response', function(res) { var data = ''; res.on('data', function(buffer) { data += buffer; }); res.on('end', function() { debug(res.statusCode, data); var json = JSON.parse(data); if (res.statusCode < 200 || res.statusCode > 299) { var err = new PythonError(json.message); err.stack = json.stack; reject(err); } else if (path === '/start_runner') { if (data.length) { accept(json); } else { reject( new Error('Request to start_runner expects data with response!') ); } } else { accept(json); } }); }); // send the request... req.end(); }); };