From b381b7bfc6b6f9b052d0e754ea265fea2dd5322a Mon Sep 17 00:00:00 2001 From: Koong Kyungmi Date: Fri, 11 Sep 2015 12:47:49 +0900 Subject: [PATCH] [IMPROVEMENT] change proxy implementation from `http-proxy` to `http-master` --- src/server/package.json | 171 +++++++++++++++++++------------------- src/server/proxy/proxy.js | 156 ++++++++++++++++++++++------------ 2 files changed, 191 insertions(+), 136 deletions(-) diff --git a/src/server/package.json b/src/server/package.json index c48d49d..d212719 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -1,87 +1,88 @@ { - "name": "webida-server", - "version": "0.0.41", - "main": "./unit-manager.js", - "private": true, - "dependencies": { - "dateformat": "1.0.11", - "connect-domain" : "*", - "connect-multiparty" : "1.2.5", - "express-session": "1.9.1", - "http-proxy": "0.10.3", - "connect-mongo": "0.4.2", - "session-file-store": "0.0.12", - "connect-sqlite3": "0.9.5", - "socket.io" : "1.2.0", - "hashmap" : "1.0.1", - "cuid" : "1.2.1", - "jsdom": "0.10.6", - "unzip" : "0.1.9", - "fstream" : "0.1.25", - "corser": "2.0.0", - "emailjs" : "*", - "mongojs": "0.9.8", - "optimist": "0.6.0", - "underscore": "1.5.2", - "ncp": "0.4.2", - "request": "*", - "winston": "*", - "querystring": "*", - "passport": "~0.1.12", - "express": "4.10.2", - "compression": "1.2.0", - "body-parser": "1.9.2", - "cookie-parser": "1.3.3", - "on-finished": "2.3.0", - "morgan": "1.5.0", - "dnode" : "1.2.0", - "glob" : "3.2.9", - "nexpect" : "0.4.2", - "connect-ensure-login": "0.1.x", - "oauth2orize": "0.x.x", - "cryptojs": "*", - "url": "*", - "passport-local": "0.1.x", - "passport-http": "0.2.x", - "passport-http-bearer": "0.2.x", - "passport-oauth2-client-password": "0.1.x", - "ejs": "0.7.x", - "optimist": "*", - "underscore": "*", - "ssh-keygen": "*", - "async": "*", - "jquery": "*", - "passport-github": "*", - "passport-google-oauth": "*", - "nodemailer": "0.7.x", - "connect-mongo": "*", - "mysql": "2.5.3", - "line-reader": "0.2.3", - "filequeue": "0.5.0", - "graceful-fs": "3.0.2", - "ffi": "1.2.6", - "formidable": "1.0.17", - "fs-extra": "0.8.1", - "pty.js": "0.2.7-1", - "q": "1.0.1", - "q-io": "1.11.0", - "ref": "0.1.3", - "send": "0.2.0", - "shortid": "2.2.2", - "tmp": "0.0.23", - "underscore": "1.6.0", - "URIjs": "1.12.1", - "walkdir": "0.0.7", - "mkdirp": "0.5.0", - "guid": "0.0.12", - "replace": "0.2.9", - "socket.io-stream": "^0.6.0", - "terminal.js": "^1.0.3", - "lodash": "3.9.3", - "data-mapper": "*", - "cron": "^1.0.9" - }, - "devDependencies": { - "connect": "~2.13.0" - } + "name": "webida-server", + "version": "0.0.41", + "main": "./unit-manager.js", + "dependencies": { + "dateformat": "1.0.11", + "connect-domain": "*", + "connect-multiparty": "1.2.5", + "express-session": "1.9.1", + "http-master": "~1.0.18", + "connect-mongo": "0.4.2", + "session-file-store": "0.0.12", + "connect-sqlite3": "0.9.5", + "socket.io": "1.2.0", + "hashmap": "1.0.1", + "cuid": "1.2.1", + "jsdom": "0.10.6", + "unzip": "0.1.9", + "fstream": "0.1.25", + "corser": "2.0.0", + "emailjs": "*", + "mongojs": "0.9.8", + "optimist": "0.6.0", + "underscore": "1.5.2", + "ncp": "0.4.2", + "request": "*", + "winston": "*", + "querystring": "*", + "passport": "~0.1.12", + "express": "4.10.2", + "compression": "1.2.0", + "body-parser": "1.9.2", + "cookie-parser": "1.3.3", + "on-finished": "2.3.0", + "morgan": "1.5.0", + "dnode": "1.2.0", + "glob": "3.2.9", + "nexpect": "0.4.2", + "connect-ensure-login": "0.1.x", + "oauth2orize": "0.x.x", + "cryptojs": "*", + "url": "*", + "passport-local": "0.1.x", + "passport-http": "0.2.x", + "passport-http-bearer": "0.2.x", + "passport-oauth2-client-password": "0.1.x", + "ejs": "0.7.x", + "optimist": "*", + "underscore": "*", + "ssh-keygen": "*", + "async": "*", + "jquery": "*", + "passport-github": "*", + "passport-google-oauth": "*", + "nodemailer": "0.7.x", + "connect-mongo": "*", + "mysql": "2.5.3", + "line-reader": "0.2.3", + "filequeue": "0.5.0", + "graceful-fs": "3.0.2", + "ffi": "1.2.6", + "formidable": "1.0.17", + "fs-extra": "0.8.1", + "pty.js": "0.2.7-1", + "q": "1.0.1", + "q-io": "1.11.0", + "ref": "0.1.3", + "send": "0.2.0", + "shortid": "2.2.2", + "tmp": "0.0.23", + "underscore": "1.6.0", + "URIjs": "1.12.1", + "walkdir": "0.0.7", + "mkdirp": "0.5.0", + "guid": "0.0.12", + "replace": "0.2.9", + "socket.io-stream": "^0.6.0", + "terminal.js": "^1.0.3", + "lodash": "3.9.3", + "data-mapper": "*", + "cron": "^1.0.9", + "jsonfile": "~2.2.1", + "node-watch": "~0.3.4" + }, + "devDependencies": { + "connect": "~2.13.0" + } } diff --git a/src/server/proxy/proxy.js b/src/server/proxy/proxy.js index 8158cad..c92312e 100644 --- a/src/server/proxy/proxy.js +++ b/src/server/proxy/proxy.js @@ -1,12 +1,12 @@ /* * Copyright (c) 2012-2015 S-Core Co., Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,53 +23,109 @@ var baseSvc = require('../common/n-svc').Svc; var express = require('express'); var fs = require('fs'); -var ejs = require('ejs'); var ProxySvr = function (svc, svrName, conf) { baseSvr.call(this, svc, svrName, conf); this.httpServer = null; this.httpsServer = null; - this.httpProxy = require('http-proxy'); + this.httpProxy = new (require('http-master'))(); + this.httpProxy.on('logNotice', logger.info); + this.httpProxy.on('logError', logger.error); logger.info('ProxySvr constructor'); extend(ProxySvr, baseSvr); }; -var errorTemplate; - -ProxySvr.prototype.start = function () { +ProxySvr.prototype.loadConfig = function (cb) { var self = this; - var conf = self.svc.config; var config = global.app.config; - var options = { - router: global.app.config.routingTablePath - }; - var forceHttps = conf.forceHttps; + var jsfile = require('jsonfile'); - function renderErrorPage(res, err){ - res.writeHead(500, {'Content-Type': 'text/html'}); - res.end(ejs.render(errorTemplate, {error: err})); - } + jsfile.readFile(config.routingTablePath, function (err, table) { + if (err) { + logger.error('read routing table failed', err); + cb(err, null); + } else { + var conf = self.svc.config; + var forceHttps = conf.forceHttps; + var options = { + //workerCount: require('os').cpus().length, + ports: {}, + errorHtmlFile: __dirname + '/views/error.ejs' + }; - function createProxyServer(host, port, options) { - var server = self.httpProxy.createServer(host, options).listen(port); - server.proxy.on('proxyError', function (err, req, res) { - if(!errorTemplate) { - fs.readFile(__dirname + '/views/error.ejs', 'utf-8', function (fileError, template) { - if (fileError) { - res.writeHead(500, {'Content-Type': 'text/html'}); - res.end('Something went wrong. We will fix it as soon as possible.'); - } else { - errorTemplate = template; - renderErrorPage(res, err); + /* fill http options */ + if (!forceHttps) { + if (conf.httpHost && conf.httpPort) { + options.ports[conf.httpPort] = { + router: table.router + }; + } + } + + /* fill https options */ + if (conf.httpsHost && conf.httpsPort) { + var caExist = fs.existsSync(config.sslCaPath); + var keyExist = fs.existsSync(config.sslKeyPath); + var certExist = fs.existsSync(config.sslCertPath); + + if (caExist && keyExist && certExist) { + options.ports[conf.httpsPort] = { + router: table.router, + ssl: { + ca: config.sslCaPath, + key: config.sslKeyPath, + cert: config.sslCertPath + } + }; + } else { + logger.info('Can not find key or cert file. So does not listen https request'); + } + } + + logger.debug('options', JSON.stringify(options, null, 4)); + cb(null, options); + } + }); +}; + +ProxySvr.prototype.reload = function () { + var self = this; + + logger.info('reload proxy due to config change'); + self.loadConfig(function (err, options) { + if (err) { + logger.error('fail to load config. ignore config change...'); + } else { + var startTime; + var proxy = self.httpProxy; + startTime = new Date().getTime(); + /* + * http-master reload does not work properly. + * so close all servers before reload servers with new config. + */ + proxy.reload({}, function() { + //if (e1) { + // logger.error('failed to stop all servers', e1); + //} + proxy.reload(options, function (e) { + if (e) { + logger.error('failed to reload proxy. ignore error', e); } + logger.info('proxy reloaded, downtime was ' + + (new Date().getTime() - startTime) + 'ms'); }); - } else { - renderErrorPage(res, err); - } - }); - } + }); + } + }); +}; + +ProxySvr.prototype.start = function () { + var self = this; + var conf = self.svc.config; + var config = global.app.config; + var forceHttps = conf.forceHttps; if (forceHttps) { var http = express(); @@ -78,25 +134,25 @@ ProxySvr.prototype.start = function () { res.redirect('https://' + req.hostname + req.url); }); http.listen(80); - } else { - createProxyServer(conf.httpHost,conf.httpPort, options); } - if (conf.httpsHost && conf.httpsPort) { - var keyExist = fs.existsSync(config.sslKeyPath); - var certExist = fs.existsSync(config.sslCertPath); - - if (keyExist && certExist) { - options.https = { - ca: fs.readFileSync('/var/webida/keys/AlphaSSLroot.crt', 'utf8'), - key: fs.readFileSync(config.sslKeyPath, 'utf8'), - cert: fs.readFileSync(config.sslCertPath, 'utf8') - }; - createProxyServer(conf.httpsHost,conf.httpsPort, options); - } else { - console.log('Can not find key or cert file. So does not listen https request'); + self.loadConfig(function (err, options) { + if (err) { + logger.error('fail to load config'); + throw err; } - } + self.httpProxy.init(options, function (err) { + if (err) { + logger.error('failed to start proxy'); + throw err; + } + + var watch = require('node-watch'); + watch(config.routingTablePath, function () { + self.reload(); + }); + }); + }); }; ProxySvr.prototype.stop = function () { @@ -145,5 +201,3 @@ ProxySvc.prototype.stopped = function () { }; exports.Svc = ProxySvc; - -