Telegram Web, preconfigured for usage in I2P. http://web.telegram.i2p/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

215 lines
5.2 KiB

var spawn = require('child_process').spawn;
var path = require('path');
var fs = require('fs');
var rimraf = require('rimraf');
var log = require('../logger').create('launcher');
var env = process.env;
var BEING_CAPTURED = 1;
var CAPTURED = 2;
var BEING_KILLED = 3;
var FINISHED = 4;
var BEING_TIMEOUTED = 5;
var BaseBrowser = function(id, emitter, captureTimeout, retryLimit) {
var self = this;
var capturingUrl;
var exitCallbacks = [];
this.killTimeout = 2000;
this.id = id;
this.state = null;
this._tempDir = path.normalize((env.TMPDIR || env.TMP || env.TEMP || '/tmp') + '/karma-' +
id.toString());
this.start = function(url) {
capturingUrl = url;
self.state = BEING_CAPTURED;
try {
log.debug('Creating temp dir at ' + self._tempDir);
fs.mkdirSync(self._tempDir);
} catch (e) {}
self._start(capturingUrl + '?id=' + self.id);
if (captureTimeout) {
setTimeout(self._onTimeout, captureTimeout);
}
};
this._start = function(url) {
self._execCommand(self._getCommand(), self._getOptions(url));
};
this.markCaptured = function() {
if (self.state === BEING_CAPTURED) {
self.state = CAPTURED;
}
};
this.isCaptured = function() {
return self.state === CAPTURED;
};
this.kill = function(callback) {
var exitCallback = callback || function() {};
log.debug('Killing %s', self.name);
if (self.state === FINISHED) {
process.nextTick(exitCallback);
} else if (self.state === BEING_KILLED) {
exitCallbacks.push(exitCallback);
} else {
self.state = BEING_KILLED;
self._process.kill();
exitCallbacks.push(exitCallback);
setTimeout(self._onKillTimeout, self.killTimeout);
}
};
this._onKillTimeout = function() {
if (self.state !== BEING_KILLED) {
return;
}
log.warn('%s was not killed in %d ms, sending SIGKILL.', self.name, self.killTimeout);
self._process.kill('SIGKILL');
};
this._onTimeout = function() {
if (self.state !== BEING_CAPTURED) {
return;
}
log.warn('%s have not captured in %d ms, killing.', self.name, captureTimeout);
self.state = BEING_TIMEOUTED;
self._process.kill();
};
this.toString = function() {
return self.name;
};
this._getCommand = function() {
var cmd = path.normalize(env[self.ENV_CMD] || self.DEFAULT_CMD[process.platform]);
if (!cmd) {
log.error('No binary for %s browser on your platform.\n\t' +
'Please, set "%s" env variable.', self.name, self.ENV_CMD);
}
return cmd;
};
this._execCommand = function(cmd, args) {
// normalize the cmd, remove quotes (spawn does not like them)
if (cmd.charAt(0) === cmd.charAt(cmd.length - 1) && '\'`"'.indexOf(cmd.charAt(0)) !== -1) {
cmd = cmd.substring(1, cmd.length - 1);
log.warn('The path should not be quoted.\n Normalized the path to %s', cmd);
}
log.debug(cmd + ' ' + args.join(' '));
self._process = spawn(cmd, args);
var errorOutput = '';
self._process.on('close', function(code) {
self._onProcessExit(code, errorOutput);
});
self._process.on('error', function(err) {
if (err.code === 'ENOENT') {
retryLimit = 0;
errorOutput = 'Can not find the binary ' + cmd + '\n\t' +
'Please set env variable ' + self.ENV_CMD;
} else {
errorOutput += err.toString();
}
});
// Node 0.8 does not emit the error
if (process.versions.node.indexOf('0.8') === 0) {
self._process.stderr.on('data', function(data) {
var msg = data.toString();
if (msg.indexOf('No such file or directory') !== -1) {
retryLimit = 0;
errorOutput = 'Can not find the binary ' + cmd + '\n\t' +
'Please set env variable ' + self.ENV_CMD;
} else {
errorOutput += msg;
}
});
}
};
this._onProcessExit = function(code, errorOutput) {
log.debug('Process %s exitted with code %d', self.name, code);
if (self.state === BEING_CAPTURED) {
log.error('Cannot start %s\n\t%s', self.name, errorOutput);
}
if (self.state === CAPTURED) {
log.error('%s crashed.\n\t%s', self.name, errorOutput);
}
retryLimit--;
if (self.state === BEING_CAPTURED || self.state === BEING_TIMEOUTED) {
if (retryLimit > 0) {
return self._cleanUpTmp(function() {
log.info('Trying to start %s again.', self.name);
self.start(capturingUrl);
});
} else {
emitter.emit('browser_process_failure', self);
}
}
self.state = FINISHED;
self._cleanUpTmp(function(err) {
exitCallbacks.forEach(function(exitCallback) {
exitCallback(err);
});
exitCallbacks = [];
});
};
this._cleanUpTmp = function(done) {
log.debug('Cleaning temp dir %s', self._tempDir);
rimraf(self._tempDir, done);
};
this._getOptions = function(url) {
return [url];
};
};
var baseBrowserDecoratorFactory = function(id, emitter, timeout) {
return function(self) {
BaseBrowser.call(self, id, emitter, timeout, 3);
};
};
baseBrowserDecoratorFactory.$inject = ['id', 'emitter', 'config.captureTimeout'];
// PUBLISH
exports.BaseBrowser = BaseBrowser;
exports.decoratorFactory = baseBrowserDecoratorFactory;