UNPKG

mobile-cli-lib

Version:
208 lines (207 loc) 9.5 kB
"use strict"; var url = require("url"); var Future = require("fibers/future"); var helpers = require("./helpers"); var zlib = require("zlib"); var util = require("util"); var progress = require("progress-stream"); var filesize = require("filesize"); var HttpClient = (function () { function HttpClient($logger, $staticConfig, $config) { this.$logger = $logger; this.$staticConfig = $staticConfig; this.$config = $config; } HttpClient.prototype.httpRequest = function (options, proxySettings) { var _this = this; return (function () { if (_.isString(options)) { options = { url: options, method: "GET" }; } var unmodifiedOptions = _.clone(options); if (options.url) { var urlParts = url.parse(options.url); if (urlParts.protocol) { options.proto = urlParts.protocol.slice(0, -1); } options.host = urlParts.hostname; options.port = urlParts.port; options.path = urlParts.path; delete options.url; } var requestProto = options.proto || "http"; delete options.proto; var body = options.body; delete options.body; var pipeTo = options.pipeTo; delete options.pipeTo; var proto = _this.$config.USE_PROXY ? "http" : requestProto; var http = require(proto); options.headers = options.headers || {}; var headers = options.headers; if (proxySettings || _this.$config.USE_PROXY) { options.path = requestProto + "://" + options.host + options.path; headers.Host = options.host; options.host = (proxySettings && proxySettings.hostname) || _this.$config.PROXY_HOSTNAME; options.port = (proxySettings && proxySettings.port) || _this.$config.PROXY_PORT; _this.$logger.trace("Using proxy with host: %s, port: %d, path is: %s", options.host, options.port, options.path); } if (!headers.Accept || headers.Accept.indexOf("application/json") < 0) { if (headers.Accept) { headers.Accept += ", "; } else { headers.Accept = ""; } headers.Accept += "application/json; charset=UTF-8, */*;q=0.8"; } if (!headers["User-Agent"]) { if (!_this.defaultUserAgent) { _this.defaultUserAgent = util.format("%sCLI/%s (Node.js %s; %s; %s)", _this.$staticConfig.CLIENT_NAME, _this.$staticConfig.version, process.versions.node, process.platform, process.arch); _this.$logger.debug("User-Agent: %s", _this.defaultUserAgent); } headers["User-Agent"] = _this.defaultUserAgent; } if (!headers["Accept-Encoding"]) { headers["Accept-Encoding"] = "gzip,deflate"; } var result = new Future(), timerId; if (options.timeout) { timerId = setTimeout(function () { _this.setResponseResult(result, timerId, { err: new Error("Request to " + unmodifiedOptions.url + " timed out.") }); }, options.timeout); delete options.timeout; } _this.$logger.trace("httpRequest: %s", util.inspect(options)); var request = http.request(options, function (response) { var data = []; var isRedirect = helpers.isResponseRedirect(response); var successful = helpers.isRequestSuccessful(response); if (!successful) { pipeTo = undefined; } var responseStream = response; switch (response.headers["content-encoding"]) { case "gzip": responseStream = responseStream.pipe(zlib.createGunzip()); break; case "deflate": responseStream = responseStream.pipe(zlib.createInflate()); break; } if (pipeTo) { pipeTo.on("finish", function () { _this.$logger.trace("httpRequest: Piping done. code = %d", response.statusCode.toString()); _this.setResponseResult(result, timerId, { response: response }); }); pipeTo = _this.trackDownloadProgress(pipeTo); responseStream.pipe(pipeTo); } else { responseStream.on("data", function (chunk) { data.push(chunk); }); responseStream.on("end", function () { _this.$logger.trace("httpRequest: Done. code = %d", response.statusCode.toString()); var responseBody = data.join(""); if (successful || isRedirect) { _this.setResponseResult(result, timerId, { body: responseBody, response: response }); } else { var errorMessage = _this.getErrorMessage(response, responseBody); var err = new Error(errorMessage); err.response = response; err.body = responseBody; _this.setResponseResult(result, timerId, { err: err }); } }); } }); request.on("error", function (err) { _this.setResponseResult(result, timerId, { err: err }); }); _this.$logger.trace("httpRequest: Sending:\n%s", _this.$logger.prepare(body)); if (!body || !body.pipe) { request.end(body); } else { body.pipe(request); } var response = result.wait(); if (helpers.isResponseRedirect(response.response)) { if (response.response.statusCode === 303) { unmodifiedOptions.method = "GET"; } _this.$logger.trace("Begin redirected to %s", response.headers.location); unmodifiedOptions.url = response.headers.location; return _this.httpRequest(unmodifiedOptions).wait(); } return response; }).future()(); }; HttpClient.prototype.setResponseResult = function (result, timerId, resultData) { if (timerId) { clearTimeout(timerId); timerId = null; } if (!result.isResolved()) { if (resultData.err) { return result.throw(resultData.err); } var finalResult = resultData; finalResult.headers = resultData.response.headers; result.return(finalResult); } }; HttpClient.prototype.trackDownloadProgress = function (pipeTo) { var _this = this; var lastMessageSize = 0, carriageReturn = "\x1B[0G", timeElapsed = 0; var progressStream = progress({ time: 1000 }, function (progress) { timeElapsed = progress.runtime; if (timeElapsed >= 1) { _this.$logger.write("%s%s", carriageReturn, Array(lastMessageSize + 1).join(" ")); var message = util.format("%sDownload progress ... %s | %s | %s/s", carriageReturn, Math.floor(progress.percentage) + "%", filesize(progress.transferred), filesize(progress.speed)); _this.$logger.write(message); lastMessageSize = message.length; } }); progressStream.on("finish", function () { if (timeElapsed >= 1) { _this.$logger.out("%s%s%s%s", carriageReturn, Array(lastMessageSize + 1).join(" "), carriageReturn, "Download completed."); } }); progressStream.pipe(pipeTo); return progressStream; }; HttpClient.prototype.getErrorMessage = function (response, body) { if (response.statusCode === 402) { var subscriptionUrl = util.format("%s://%s/appbuilder/account/subscription", this.$config.AB_SERVER_PROTO, this.$config.AB_SERVER); return util.format("Your subscription has expired. Go to %s to manage your subscription. Note: After you renew your subscription, " + "log out and log back in for the changes to take effect.", subscriptionUrl); } else { try { var err = JSON.parse(body); if (_.isString(err)) { return err; } if (err.ExceptionMessage) { return err.ExceptionMessage; } if (err.Message) { return err.Message; } } catch (parsingFailed) { return "The server returned unexpected response: " + parsingFailed.toString(); } return body; } }; return HttpClient; }()); exports.HttpClient = HttpClient; $injector.register("httpClient", HttpClient);