UNPKG

4.97 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([
178 async.apply(download, options),
179 async.apply(run, options)
180 ], callback)
181}
182
183module.exports = downloadAndRun
184module.exports.kill = killTunnel