UNPKG

5.12 kBJavaScriptView Raw
1'use strict';
2
3var async = require('async');
4var fs = require('fs');
5var os = require('os');
6var path = require('path');
7var spawn = require('child_process').spawn;
8var downloader = require('./downloader');
9var tunnelLocation = undefined;
10var activeTunnel = undefined;
11var started = false;
12
13function logger(msg) {
14 console.log.apply(console, arguments);
15}
16
17function download(options, callback) {
18 tunnelLocation = path.normalize(path.join(__dirname, '../testingbot-tunnel.jar'));
19
20 var url = 'https://testingbot.com/tunnel/testingbot-tunnel.jar';
21
22 if (options.tunnelVersion) {
23 tunnelLocation = path.normalize(path.join(__dirname, '../testingbot-tunnel-' + options.tunnelVersion + '.jar'));
24 url = 'https://testingbot.com/tunnel/testingbot-tunnel-' + options.tunnelVersion + '.jar';
25 }
26
27 try {
28 var tunnelFile = fs.statSync(tunnelLocation);
29 if (tunnelFile['size'] > 1024) {
30 return callback(null);
31 }
32 } catch (ignore) {}
33
34 downloader.get(url, { fileName: 'testingbot-tunnel', destination: tunnelLocation }, function (err, destination) {
35 if (err) {
36 return callback(new Error('Could not download the tunnel from TestingBot - please check your connection. ' + err.message));
37 }
38
39 return callback(null);
40 });
41}
42
43function run(options, callback) {
44 if (!fs.existsSync(tunnelLocation)) {
45 return callback(new Error('Tunnel jar file is not present in ' + tunnelLocation));
46 }
47
48 var onReady = function onReady() {
49 started = true;
50 logger('Tunnel is ready');
51 callback(null, activeTunnel);
52 };
53
54 var args = [];
55
56 args.push('-jar');
57 args.push(tunnelLocation);
58
59 if (options.apiKey) {
60 args.push(options.apiKey);
61 }
62
63 if (options.apiSecret) {
64 args.push(options.apiSecret);
65 }
66
67 for (var option in options) {
68 if (option === 'apiKey' || option === 'apiSecret' || option === 'verbose' || option === 'tunnelVersion') {
69 continue;
70 }
71
72 if (options[option]) {
73 args.push('--' + option);
74 args.push(options[option]);
75 } else {
76 args.push('--' + option);
77 }
78 }
79
80 var readyFile = path.join(os.tmpdir(), 'testingbot.ready');
81 try {
82 if (fs.statSync(readyFile).isFile()) {
83 logger('Tunnel Readyfile already exists, removing');
84 fs.unlinkSync(readyFile);
85 }
86 } catch (ignore) {}
87
88 args.push('-f');
89 args.push(readyFile);
90
91 var readyFileChecker = setInterval(function () {
92 fs.stat(readyFile, function (error, stat) {
93 if (!error) {
94 clearInterval(readyFileChecker);
95 onReady();
96 }
97 });
98 }, 800);
99
100 if (options.verbose) {
101 logger('Starting tunnel with options', args);
102 }
103 activeTunnel = spawn('java', args, {
104 detached: true
105 });
106
107 activeTunnel.unref();
108
109 activeTunnel.stderr.on('data', function (data) {
110 data = data.toString().trim();
111 if (options.verbose && data !== '') {
112 logger(data);
113 }
114 if (data.indexOf('is available for download') > -1 || data.indexOf('An error ocurred') > -1) {
115 logger(data);
116 } else if (data.toLowerCase().indexOf('error') > -1) {
117 logger(data);
118 }
119 });
120
121 activeTunnel.stdout.on('data', function (data) {
122 data = data.toString().trim();
123 if (options.verbose && data !== '') {
124 logger(data);
125 }
126 });
127
128 activeTunnel.close = function (closeCallback) {
129 if (closeCallback) {
130 activeTunnel.on('close', function () {
131 closeCallback();
132 });
133 }
134 activeTunnel.kill('SIGINT');
135 };
136
137 activeTunnel.on('exit', function (code, signal) {
138 logger('Closing TestingBot Tunnel');
139 if (!started) {
140 callback(new Error('Could not start TestingBot Tunnel. Exit code ' + code + ' signal: ' + signal));
141 }
142
143 started = false;
144 activeTunnel = null;
145 });
146}
147
148function killTunnel(callback) {
149 if (!callback) {
150 callback = function () {};
151 }
152
153 if (!activeTunnel) {
154 return callback(new Error('no active tunnel'));
155 }
156
157 activeTunnel.kill('SIGINT');
158}
159
160function downloadAndRun(options, callback) {
161 if (!options) {
162 options = {};
163 }
164
165 if (!callback) {
166 callback = function () {};
167 }
168
169 async.waterfall([async.apply(download, options), async.apply(run, options)], callback);
170}
171
172function exitHandler(options, err) {
173 if (!activeTunnel) {
174 return;
175 }
176
177 if (err) {
178 logger(err.stack);
179 }
180
181 if (options.cleanup) {
182 logger('Shutting down tunnel');
183 killTunnel();
184 }
185
186 if (options.exit) {
187 process.exit();
188 }
189}
190
191process.on('exit', exitHandler.bind(null, { cleanup: true }));
192process.on('SIGINT', exitHandler.bind(null, { exit: true }));
193process.on('uncaughtException', exitHandler.bind(null, { exit: true }));
194
195module.exports = downloadAndRun;
196module.exports.kill = killTunnel;