webshot-factory
Version:
screenshots at scale based on headless chrome
135 lines • 5.4 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const puppeteer = require("puppeteer");
const Logger = require("log4js");
const P = require("bluebird");
let _logger = Logger.getLogger("shot-worker");
const DEBUG_PORT_OFFSET = 9201;
class ShotWorker {
constructor(id) {
this.id = id;
this.timeout = 60000;
this.shotCallback = _.noop;
this.isBusy = true;
}
static create(idx, config) {
return __awaiter(this, void 0, void 0, function* () {
let worker = new ShotWorker(idx);
worker.config = config;
yield worker.init(idx, config.callbackName, config.warmerUrl, config.width, config.height, config.timeout);
return worker;
});
}
takeShot(url) {
if (this.isBusy) {
_logger.error('Worker is busy doing work');
return P.reject('Worker is already busy');
}
let start = (new Date()).valueOf();
this.isBusy = true;
_logger.debug(`screenshot url #${this.id}: ${url}`);
return new P((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
this.shotCallback = (err, buffer) => __awaiter(this, void 0, void 0, function* () {
if (err) {
return reject(err);
}
resolve(buffer);
});
this.page.goto(url, {
waitUntil: 'networkidle2'
}).then(() => __awaiter(this, void 0, void 0, function* () {
if (!this.config.callbackName) {
let buffer = yield this.page.screenshot({
fullPage: true
});
this.shotCallback(null, buffer);
}
})).then(null, (err) => {
this.shotCallback(err, null);
});
}))
.timeout(this.timeout)
.finally(() => {
_logger.debug(`Worker #${this.id}: Screenshot Complete.`);
this.isBusy = false;
});
}
reload() {
return this.page.reload();
}
exit() {
this.browser && this.browser.close();
}
getStatus() {
return {
id: this.id,
browser: this.browser,
debugPort: this.debugPort,
isBusy: this.isBusy
};
}
init(idx = 0, callbackName = '', warmerUrl = '', width = 800, height = 600, timeout = 60000, chromeExecutablePath = '') {
return __awaiter(this, void 0, void 0, function* () {
this.debugPort = DEBUG_PORT_OFFSET + idx;
this.timeout = timeout;
let start = (new Date()).valueOf();
let options = {
ignoreHTTPSErrors: true,
headless: true,
args: [
'--ignore-certificate-errors',
'--enable-precise-memory-info',
`--remote-debugging-port=${this.debugPort}`
],
userDataDir: '/tmp/chrome'
};
if (chromeExecutablePath) {
options.executablePath = chromeExecutablePath;
}
try {
this.browser = yield puppeteer.launch(options);
_logger.debug('puppeteer launched');
}
catch (error) {
_logger.error("error launching chrome from puppeteer", error);
}
this.page = yield this.browser.newPage();
this.page.on('console', (...args) => _logger.debug(`PAGE LOG Worker #${idx}:`, ...args));
this.page.on('response', r => _logger.debug(`Worker #${idx}: ${r.status} ${r.url}`));
this.page.setViewport({
width: width,
height: height
});
// Define a window.onCustomEvent function on the page.
if (callbackName) {
yield this.page.exposeFunction(callbackName, e => {
_logger.debug('Callback called from browser with', e);
return this.page.screenshot({
fullPage: true
}).then((buffer) => {
this.shotCallback(null, buffer);
}, (err) => {
this.shotCallback(err, null);
});
});
}
if (warmerUrl) {
yield this.page.goto(warmerUrl, { waitUntil: 'networkidle2' });
}
_logger.info(`Worker ${idx} ready`);
this.creationTime = (new Date()).valueOf() - start;
this.isBusy = false;
});
}
}
exports.ShotWorker = ShotWorker;
//# sourceMappingURL=shot-worker.js.map