diff --git a/package.json b/package.json index e103b526..3fffe05d 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,11 @@ "mixpanel": "0.0.20", "network-checker": "~0.0.2", "ngrok": "~0.1.97", + "pinejs-client": "^1.2.0", "pubnub": "~3.6.4", "randomstring": "~1.0.3", "request": "^2.51.0", - "pinejs-client": "^1.2.0", + "server-destroy": "^1.0.0", "sqlite3": "~3.0.4", "tty.js": "~0.2.13", "typed-error": "~0.1.0" diff --git a/src/api.coffee b/src/api.coffee index c29c719f..31827bda 100644 --- a/src/api.coffee +++ b/src/api.coffee @@ -37,7 +37,7 @@ module.exports = (secret) -> if !app? throw new Error('App not found') tty.start(app) - .then (url) -> + .then ({url}) -> res.status(200).send(url) .catch (err) -> res.status(503).send(err?.message or err or 'Unknown error') diff --git a/src/lib/tty.coffee b/src/lib/tty.coffee index 30c294db..7d1ba042 100644 --- a/src/lib/tty.coffee +++ b/src/lib/tty.coffee @@ -6,9 +6,11 @@ TypedError = require 'typed-error' # to reduce memory in the likely case they are never used. ngrok = null tty = null +enableDestroy = null init = _.once -> ngrok = Promise.promisifyAll require 'ngrok' tty = Promise.promisifyAll require 'tty.js' + enableDestroy = require 'server-destroy' class DisconnectedError extends TypedError @@ -21,23 +23,28 @@ exports.start = (app) -> apps[app.id] ?= Promise.rejected() return apps[app.id] = apps[app.id].catch -> port = nextPort++ - tty.createServer + server = tty.createServer shell: './src/enterContainer.sh' shellArgs: do -> i = 0 return (session) -> [ app.containerId, session.id, i++ ] static: __dirname + '/static' - .listenAsync(port, null) - .then -> - ngrok.connectAsync(port) + enableDestroy(server.server) + Promise.props + server: server.listenAsync(port, null).return(server.server) + url: ngrok.connectAsync(port) exports.stop = (app) -> if !apps[app.id]? return Promise.resolve() - apps[app.id] = apps[app.id].then (url) -> - # ngrok must have been loaded already or we wouldn't have a url to disconnect from. - ngrok.disconnectAsync(url) - .then -> - # We throw an error so that `.start` will catch and restart the session. - throw new DisconnectedError() + apps[app.id] = apps[app.id].then ({server, url}) -> + destroy = Promise.promisify(server.destroy, server) + Promise.join( + destroy() + # ngrok must have been loaded already or we wouldn't have a url to disconnect from. + ngrok.disconnectAsync(url) + -> + # We throw an error so that `.start` will catch and restart the session. + throw new DisconnectedError() + ) return apps[app.id].catch DisconnectedError, -> # All good, since we want to disconnect here!