UNPKG

5.02 kBJavaScriptView Raw
1'use strict';
2
3const async = require('async');
4const fs = require('fs');
5const os = require('os');
6const path = require('path');
7const spawn = require('child_process').spawn;
8const downloader = require('./downloader');
9let tunnelLocation;
10let activeTunnel;
11let 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 let 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 const 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 }, (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 const checkJava = spawn('java');
49 checkJava.on('error', err => {
50 return callback(new Error(`Java might not be installed, necessary to use testingbot-tunnel ${err.message}`));
51 });
52
53 const onReady = function () {
54 started = true;
55 logger('Tunnel is ready');
56 callback(null, activeTunnel);
57 };
58
59 const args = [];
60
61 args.push('-jar');
62 args.push(tunnelLocation);
63
64 if (options.apiKey) {
65 args.push(options.apiKey);
66 }
67
68 if (options.apiSecret) {
69 args.push(options.apiSecret);
70 }
71
72 for (const option in options) {
73 if (option === 'apiKey' || option === 'apiSecret' || option === 'verbose' || option === 'tunnelVersion') {
74 continue;
75 }
76
77 if (options[option]) {
78 args.push(`--${option}`);
79 args.push(options[option]);
80 } else {
81 args.push(`--${option}`);
82 }
83 }
84
85 const readyFile = path.join(os.tmpdir(), 'testingbot.ready');
86 try {
87 if (fs.statSync(readyFile).isFile()) {
88 logger('Tunnel Readyfile already exists, removing');
89 fs.unlinkSync(readyFile);
90 }
91 } catch (ignore) {}
92
93 args.push(`-f`);
94 args.push(readyFile);
95
96 const readyFileChecker = setInterval(() => {
97 fs.stat(readyFile, (error, stat) => {
98 if (!error) {
99 clearInterval(readyFileChecker);
100 onReady();
101 }
102 });
103 }, 800);
104
105 if (options.verbose) {
106 logger('Starting tunnel with options', args);
107 }
108 activeTunnel = spawn('java', args, {});
109
110 activeTunnel.stderr.on('data', data => {
111 data = data.toString().trim();
112 if (options.verbose && data !== '') {
113 logger(data);
114 }
115 if (data.indexOf('is available for download') > -1) {
116 logger(data);
117 }
118 if (data.indexOf('error code : 401') > -1) {
119 activeTunnel.error = 'Invalid credentials. Please supply the correct key/secret obtained from TestingBot.com';
120 activeTunnel.close();
121 } else if (data.toLowerCase().indexOf('error') > -1) {
122 logger(data);
123 activeTunnel.error = data;
124 activeTunnel.close();
125 }
126 });
127
128 activeTunnel.stdout.on('data', data => {
129 data = data.toString().trim();
130 if (options.verbose && data !== '') {
131 logger(data);
132 }
133 });
134
135 activeTunnel.close = closeCallback => {
136 if (closeCallback) {
137 activeTunnel.on('close', () => {
138 closeCallback();
139 });
140 }
141 activeTunnel.kill('SIGINT');
142 };
143
144 activeTunnel.on('exit', (code, signal) => {
145 logger('Closing TestingBot Tunnel');
146 if (!started) {
147 callback(new Error(activeTunnel.error ? activeTunnel.error : `Could not start TestingBot Tunnel. Exit code ${code} signal: ${signal}`));
148 }
149
150 started = false;
151 activeTunnel = null;
152 });
153}
154
155function killTunnel(callback) {
156 if (!callback) {
157 callback = function () {};
158 }
159
160 if (!activeTunnel) {
161 return callback(new Error('no active tunnel'));
162 }
163
164 activeTunnel.kill('SIGINT');
165 callback(null);
166}
167
168function downloadAndRun(options, callback) {
169 if (!options) {
170 options = {};
171 }
172
173 if (!callback) {
174 callback = function () {};
175 }
176
177 async.waterfall([async.apply(download, options), async.apply(run, options)], callback);
178}
179
180module.exports = downloadAndRun;
181module.exports.kill = killTunnel;