@tririga/tri-proxy
Version:
A development HTTP proxy for IBM TRIRIGA UX views.
195 lines (178 loc) • 5.19 kB
JavaScript
"use strict";
const bs = require("browser-sync");
const path = require("path");
const url = require("url");
const fs = require("fs");
const http = require("http");
const https = require("https");
const proxyUtils = require("./proxy-utils");
class TriProxy {
constructor(target, port, views, dirs, browser) {
this.target = target;
this.port = port;
this.views = views;
this.dirs = this.stripTrailingSlash(dirs);
this.browser = browser;
this.contextPath = this.getContextPath();
this._started = false;
}
start() {
if (!this.started) {
this.server = bs.create("tri-proxy");
this.server.init(this.getServerOptions());
this.started = true;
}
}
getServerOptions() {
let serverOptions = {
proxy: {
target: this.target,
proxyRes: [
proxyUtils.checkCookies
],
cookies: {
stripDomain: false
},
},
port: this.port,
ui: false,
snippetOptions: {
rule: {
match: /<\/body>/i,
fn: function (snippet, match) {
return snippet + match;
}
}
},
serveStatic: this.getServeStaticOption(),
files: this.getFiles(),
middleware: this.getMiddleware(),
ghostMode: {
clicks: false,
scroll: false,
forms: false
},
notify:false,
}
if (this.browser && this.browser.length > 0) {
serverOptions.browser = this.browser;
}
return serverOptions;
}
getContextPath() {
if (!this.target) {
return null;
}
var matches = this.target.match(/https?:\/\/[^\/]*(\/[^\/]*)/);
return (matches && matches.length > 1 && matches[1].length > 1 && matches[1] != "/p") ? matches[1] : "";
}
getServeStaticOption() {
var serveStaticList = [];
this.views.forEach((view, index) => Array.prototype.push.apply(serveStaticList, this._createViewStaticRoutes(view, this.dirs[index])));
return serveStaticList;
}
_createViewStaticRoutes(view, dir) {
let viewStaticRoutes = [];
viewStaticRoutes.push({
route: `${this.contextPath}/p/components/r/en-US/l/${view}`,
dir: dir
});
viewStaticRoutes.push({
route: `${this.contextPath}/p/components/r/1/v/en-US/l/${view}`,
dir: dir
});
viewStaticRoutes.push({
route: `${this.contextPath}/p/components/r/3/v/en-US/l/${view}`,
dir: dir
});
return viewStaticRoutes;
}
getMiddleware() {
return [this.processTranslatedFiles.bind(this)];
}
processTranslatedFiles(req, res, next) {
if (req.headers["authorization"]) {
this.authorization = req.headers["authorization"];
}
let parsedUrl = url.parse(req.url);
let componentRegExp = new RegExp("/p/components/r/(?:([1,3])/v/)?([^/]+)/l/([^/]+)/(.+/)?([^/]+)$");
var matches = parsedUrl.pathname.match(componentRegExp);
if (matches != null) {
let polymerVersion = matches[1];
polymerVersion = !polymerVersion ? "1" : polymerVersion;
let language = matches[2];
let view = matches[3];
let pathInsideView = matches[4];
pathInsideView = !pathInsideView ? "" : pathInsideView.replace(/[\/\\]/g, path.sep);
let fileName = matches[5];
let viewIndex = this.views.indexOf(view);
if (language != "en-US" && viewIndex >= 0) {
try {
this.translateFile(req, res, polymerVersion, pathInsideView, fileName, this.dirs[viewIndex]);
} catch(e) {
next();
}
} else {
next();
}
} else {
next();
}
}
translateFile(req, res, polymerVersion, pathInsideView, fileName, dir) {
let filePath = `${dir}${path.sep}${pathInsideView}${fileName}`;
if(!fs.existsSync(filePath)) {
throw new Error("File not found");
}
let fileStream = fs.createReadStream(filePath);
let options = this.createTranslateFileRequestOptions(req, polymerVersion, fileName);
let parsedTarget = url.parse(this.target);
let protocol = parsedTarget.protocol === "https:" ? https : http;
let translatioReq = protocol.request(options, (translationResp) => {
const contentType = translationResp.headers['content-type'];
res.setHeader('Content-Type', contentType);
res.statusCode = translationResp.statusCode;
translationResp.pipe(res);
});
fileStream.pipe(translatioReq);
translatioReq.on('error', function(e){
console.error(e);
});
}
createTranslateFileRequestOptions(req, polymerVersion, fileName) {
let parsedTarget = url.parse(this.target);
var options = {
hostname: parsedTarget.hostname,
port: parsedTarget.port,
path: `${this.contextPath}/p/components/translate_tri_view/${polymerVersion}/${fileName}`,
method: "POST",
headers: {
"Cookie": req.headers["cookie"]
}
};
if (req.headers["authorization"]) {
options.headers["Authorization"] = req.headers["authorization"];
} else if (this.authorization) {
options.headers["Authorization"] = this.authorization;
}
return options;
}
getFiles() {
var files = [];
for (var i = 0, j = 0; i < this.dirs.length; ++i) {
files[j++] = this.dirs[i] + "/**/*.html";
files[j++] = this.dirs[i] + "/**/*.js";
}
return files;
}
stripTrailingSlash(dirs) {
if (!dirs) {
return null;
}
for (var index = 0; index < dirs.length; index++) {
dirs[index] = dirs[index] ? path.resolve(dirs[index]).replace(/[\\\/]+$/, "") : "";
}
return dirs;
}
};
module.exports = TriProxy;