UNPKG

11.9 kBJavaScriptView Raw
1var path = require('path');
2var fs = require('fs');
3var eventStream = require('event-stream');
4var express = require('express');
5var request = require('request');
6var httpProxy = require('http-proxy');
7var logger = require('js-logger');
8var s = require('underscore.string');
9var _ = require('lodash');
10var URI = require('urijs');
11var tiny_lr = require('tiny-lr');
12var liveReload = require('connect-livereload');
13var body = require('body-parser');
14var runningAsScript = require.main === module;
15var configFile = process.env.HAWTIO_CONFIG_FILE || 'config.js';
16// default config values
17var config = {
18 // server listen port
19 port: 2772,
20 // log level
21 logLevel: logger.INFO,
22 // path to mount the dyamic proxy
23 proxy: '/proxy',
24 // paths to connect to external services, an example config:
25 // {
26 // proto: 'http',
27 // hostname: 'localhost',
28 // port: 8282,
29 // path: '/hawtio/jolokia',
30 // targetPath: '/hawtio/jolokia'
31 // }
32 //
33 staticProxies: [],
34 // directories to search for static assets
35 staticAssets: [
36 {
37 path: '/',
38 dir: '.'
39 }
40 ],
41 fallback: null,
42 liveReload: {
43 enabled: false,
44 port: 35729
45 }
46};
47if (fs.existsSync(configFile)) {
48 var conf = require(configFile);
49 _.assign(config, conf);
50}
51logger.useDefaults(config.logLevel);
52if (runningAsScript) {
53 logger.get('hawtio-backend').info("Running as script");
54}
55/// <reference path="includes.ts" />
56var HawtioBackend;
57(function (HawtioBackend) {
58 HawtioBackend.log = logger.get('hawtio-backend');
59 HawtioBackend.app = express();
60 HawtioBackend.proxyRoutes = {};
61 var startupTasks = [];
62 var listening = false;
63 function getTargetURI(options) {
64 var target = new URI({
65 protocol: options.proto,
66 username: options.username,
67 password: options.password,
68 hostname: options.hostname,
69 port: options.port,
70 path: options.path
71 });
72 target.query(options.query);
73 var targetURI = target.toString();
74 HawtioBackend.log.debug("Target URI: ", targetURI);
75 return targetURI;
76 }
77 HawtioBackend.getTargetURI = getTargetURI;
78 function addStartupTask(cb) {
79 HawtioBackend.log.debug("Adding startup task");
80 startupTasks.push(cb);
81 if (listening) {
82 cb();
83 }
84 }
85 HawtioBackend.addStartupTask = addStartupTask;
86 function setConfig(newConfig) {
87 _.assign(config, newConfig);
88 HawtioBackend.log.setLevel(config.logLevel);
89 }
90 HawtioBackend.setConfig = setConfig;
91 var server = null;
92 var lr = null;
93 var lrServer = null;
94 function reload() {
95 return eventStream.map(function (file, callback) {
96 if (lr) {
97 lr.changed({
98 body: {
99 files: file.path
100 }
101 });
102 }
103 return callback(null, file);
104 });
105 }
106 HawtioBackend.reload = reload;
107 function use(path, func) {
108 HawtioBackend.app.use(path, func);
109 }
110 HawtioBackend.use = use;
111 function listen(cb) {
112 var lrPort = config.liveReload.port || 35729;
113 if (config.liveReload.enabled) {
114 HawtioBackend.app.use(liveReload({ port: lrPort }));
115 }
116 listening = true;
117 startupTasks.forEach(function (cb) {
118 HawtioBackend.log.debug("Executing startup task");
119 cb();
120 });
121 if (config.fallback) {
122 if (typeof config.fallback === 'string') {
123 HawtioBackend.app.use(function (req, res, next) {
124 fs.createReadStream(config.fallback).pipe(res);
125 });
126 }
127 else if (typeof config.fallback === 'object') {
128 HawtioBackend.app.use(function (req, res, next) {
129 var match = _.find(config.fallback, function (_, k) { return req.originalUrl.match(new RegExp(k)); });
130 if (match) {
131 fs.createReadStream(match).pipe(res);
132 }
133 else {
134 res.statusCode = 404;
135 res.end();
136 }
137 });
138 }
139 else {
140 HawtioBackend.log.warn("Unsupported fallback option:", config.fallback);
141 }
142 }
143 server = HawtioBackend.app.listen(config.port, function () {
144 if (config.liveReload.enabled) {
145 lr = tiny_lr();
146 lrServer = lr.listen(lrPort, function () {
147 HawtioBackend.log.info("Started livereload, port :", lrPort);
148 });
149 }
150 cb(server);
151 });
152 server.on('upgrade', function (req, socket, head) {
153 //console.log("Upgrade event for URL: ", req.url);
154 var targetUri = new URI(req.url);
155 var targetPath = targetUri.path();
156 _.forIn(HawtioBackend.proxyRoutes, function (config, route) {
157 if (s.startsWith(targetPath, route)) {
158 //console.log("Found config for route: ", route, " config: ", config);
159 if (!config.httpProxy) {
160 var proxyConfig = config.proxyConfig;
161 var target = new URI().protocol(proxyConfig.proto).host(proxyConfig.hostname).port(proxyConfig.port).path(proxyConfig.targetPath).query({}).toString();
162 console.log("Creating websocket proxy to target: ", target);
163 config.proxy = httpProxy.createProxyServer({
164 target: target,
165 secure: false,
166 ws: true
167 });
168 }
169 targetPath = targetPath.substring(route.length);
170 req.url = targetUri.path(targetPath).toString();
171 config.proxy.ws(req, socket, head);
172 }
173 });
174 });
175 return server;
176 }
177 HawtioBackend.listen = listen;
178 function stop(cb) {
179 if (lrServer) {
180 lrServer.close(function () {
181 HawtioBackend.log.info("Stopped livereload port");
182 });
183 lrServer = null;
184 }
185 if (server) {
186 server.close(function () {
187 listening = false;
188 if (cb) {
189 cb();
190 }
191 });
192 server = null;
193 }
194 }
195 HawtioBackend.stop = stop;
196 function getServer() {
197 return server;
198 }
199 HawtioBackend.getServer = getServer;
200 if (runningAsScript) {
201 server = listen(function (server) {
202 var host = server.address().address;
203 var port = server.address().port;
204 HawtioBackend.log.info("started at ", host, ":", port);
205 });
206 }
207})(HawtioBackend || (HawtioBackend = {}));
208(module).exports = HawtioBackend;
209/// <reference path="init.ts" />
210var HawtioBackend;
211(function (HawtioBackend) {
212 function proxy(uri, req, res) {
213 function handleError(e) {
214 res.status(500).end('error proxying to "' + uri + '": ' + e);
215 }
216 delete req.headers.referer;
217 var r = request({ method: req.method, uri: uri, json: req.body, headers: req.headers });
218 req.on('error', handleError)
219 .pipe(r)
220 .on('error', handleError)
221 .on('response', function (res2) {
222 if (res2.statusCode === 401 || res2.statusCode === 403) {
223 HawtioBackend.log.info("Authentication failed on remote server:", res2.statusCode, res2.statusMessage, uri);
224 HawtioBackend.log.debug("Response headers:\n", res2.headers);
225 res.header(res2.headers).sendStatus(res2.statusCode);
226 }
227 else {
228 if (res2.headers['content-type']) {
229 res.header('content-type', res2.headers['content-type']);
230 }
231 res.status(res2.statusCode);
232 res2.pipe(res).on('error', handleError);
233 }
234 });
235 }
236 HawtioBackend.addStartupTask(function () {
237 var index = 0;
238 config.staticProxies.forEach(function (proxyConfig) {
239 index = index + 1;
240 _.defaults(proxyConfig, {
241 path: '/proxy-' + index,
242 hostname: 'localhost',
243 port: 80,
244 proto: 'http',
245 targetPath: '/proxy-' + index
246 });
247 HawtioBackend.log.debug("adding static proxy config: \n", proxyConfig);
248 var router = express.Router();
249 router.use('/', function (req, res, next) {
250 var path = [s.rtrim(proxyConfig.targetPath, '/'), s.ltrim(req.path, '/')].join('/');
251 var uri = HawtioBackend.getTargetURI({
252 proto: proxyConfig.proto,
253 username: proxyConfig.username,
254 password: proxyConfig.password,
255 hostname: proxyConfig.hostname,
256 port: proxyConfig.port,
257 path: path,
258 query: req.query
259 });
260 req.headers.host = proxyConfig.hostname;
261 proxy(uri, req, res);
262 });
263 HawtioBackend.app.use(proxyConfig.path, router);
264 HawtioBackend.proxyRoutes[proxyConfig.path] = {
265 proxyConfig: proxyConfig,
266 router: router
267 };
268 });
269 });
270 // dynamic proxy
271 var proxyRouter = express.Router();
272 proxyRouter.param('proto', function (req, res, next, proto) {
273 HawtioBackend.log.debug("requesting proto: ", proto);
274 switch (proto.toLowerCase()) {
275 case 'http':
276 case 'https':
277 next();
278 break;
279 default:
280 res.status(406).send('Invalid protocol: "' + proto + '"');
281 }
282 });
283 proxyRouter.param('hostname', function (req, res, next, hostname) {
284 HawtioBackend.log.debug("requesting hostname: ", hostname);
285 next();
286 });
287 proxyRouter.param('port', function (req, res, next, port) {
288 HawtioBackend.log.debug("requesting port: ", port);
289 var portNumber = s.toNumber(port);
290 HawtioBackend.log.debug("parsed port number: ", portNumber);
291 if (isNaN(portNumber)) {
292 res.status(406).send('Invalid port number: "' + port + '"');
293 }
294 else {
295 next();
296 }
297 });
298 proxyRouter.use('/', function (req, res, next) {
299 if (req.path === '') {
300 res.status(200).end();
301 }
302 else {
303 next();
304 }
305 });
306 proxyRouter.use('/:proto/:hostname/:port/', function (req, res, next) {
307 var uri = HawtioBackend.getTargetURI({
308 proto: req.params.proto,
309 hostname: req.params.hostname,
310 port: req.params.port,
311 path: req.path,
312 query: req.query
313 });
314 proxy(uri, req, res);
315 });
316 HawtioBackend.addStartupTask(function () {
317 HawtioBackend.log.debug("Setting dynamic proxy mount point: ", config.proxy);
318 HawtioBackend.app.use(config.proxy, proxyRouter);
319 });
320})(HawtioBackend || (HawtioBackend = {}));
321/// <reference path="init.ts"/>
322var HawtioBackend;
323(function (HawtioBackend) {
324 function mountAsset(mount, dir) {
325 HawtioBackend.app.use(mount, express.static(path.normalize(dir)));
326 }
327 HawtioBackend.mountAsset = mountAsset;
328 HawtioBackend.addStartupTask(function () {
329 config.staticAssets.forEach(function (asset) {
330 HawtioBackend.log.info("Mounting static asset: ", asset);
331 mountAsset(asset.path, asset.dir);
332 });
333 });
334})(HawtioBackend || (HawtioBackend = {}));