Fix SVG glyphs and make the service more robust

Change-Id: I14d3ca2fdc89f8662b2e823b6c891c79db5bab5a
This commit is contained in:
Gabriel Wicke 2013-10-08 17:30:54 -07:00
parent fd8da050fb
commit 6c7f4e3b38
4 changed files with 86 additions and 69 deletions

View file

@ -57,7 +57,7 @@ window.engine = (new (function() {
// displayed like an image on some different page. // displayed like an image on some different page.
this.merge = function(svg) { this.merge = function(svg) {
var uses, var uses,
copied, copied = {},
k, k,
id, id,
texts, texts,
@ -69,7 +69,6 @@ window.engine = (new (function() {
// clone and copy all used paths into local defs. // clone and copy all used paths into local defs.
// xlink:href in uses FIX // xlink:href in uses FIX
uses = svg.getElementsByTagName('use'); uses = svg.getElementsByTagName('use');
copied = {};
for ( k = 0; k < uses.length; ++k) { for ( k = 0; k < uses.length; ++k) {
id = uses[k].getAttribute('href'); id = uses[k].getAttribute('href');
if (id && copied[id]) { if (id && copied[id]) {
@ -94,6 +93,7 @@ window.engine = (new (function() {
svg.style.position = 'static'; svg.style.position = 'static';
tmpDiv = document.createElement('div'); tmpDiv = document.createElement('div');
tmpDiv.appendChild(defs);
tmpDiv.appendChild(svg); tmpDiv.appendChild(svg);
return tmpDiv.innerHTML; return tmpDiv.innerHTML;
}; };
@ -125,7 +125,7 @@ window.engine = (new (function() {
}); });
})); }));
} catch (err) { } catch (err) {
cb([latex, err.message, '-']); cb([latex, err, err]);
} }
} }
}; };

View file

@ -39,7 +39,8 @@ page.onCallback = function(data) {
data[0].length + 'B query, ERR ' + data[1][0] + t; data[0].length + 'B query, ERR ' + data[1][0] + t;
out = JSON.stringify({err:data[1][0],svg:data[1],mml:data[2],'log':log,'sucess':false}); out = JSON.stringify({err:data[1][0],svg:data[1],mml:data[2],'log':log,'sucess':false});
resp.write(out); resp.write(out);
//console.log(log); console.log(log);
phantom.exit(1);
} }
resp.close(); resp.close();
}; };

View file

@ -10,6 +10,7 @@ var express = require('express'),
http = require('http'), http = require('http'),
fs = require('fs'), fs = require('fs'),
child_process = require('child_process'), child_process = require('child_process'),
request = require('request'),
querystring = require('querystring'); querystring = require('querystring');
var config; var config;
@ -40,28 +41,32 @@ console.log( ' - ' + instanceName + ' loading...' );
var restarts = 10; var restarts = 10;
var backend, var backend,
backendStarting = false,
backendPort, backendPort,
requestQueue = []; requestQueue = [];
var startBackend = function () { // forward declaration
if (backend) { var handleRequests;
backend.kill();
} var backendCB = function () {
var backendCB = function (err, stdout, stderr) { backendStarting = false;
if (err) { handleRequests();
restarts--;
if (restarts > 0) {
startBackend();
}
console.error(err.toString());
process.exit(1);
}
}; };
var startBackend = function (cb) {
if (backend) {
backend.removeAllListeners();
backend.kill('SIGKILL');
}
backendPort = Math.floor(9000 + Math.random() * 50000); backendPort = Math.floor(9000 + Math.random() * 50000);
console.error(instanceName + ': Starting backend on port ' + backendPort); console.error(instanceName + ': Starting backend on port ' + backendPort);
backend = child_process.exec('phantomjs main.js ' + backendPort, backendCB); backend = child_process.spawn('phantomjs', ['main.js', backendPort]);
backend.stdout.pipe(process.stdout); backend.stdout.pipe(process.stderr);
backend.stderr.pipe(process.stderr); backend.stderr.pipe(process.stderr);
backend.on('close', startBackend);
backendStarting = true;
// give backend 1 seconds to start up
setTimeout(backendCB, 1000);
}; };
startBackend(); startBackend();
@ -86,57 +91,67 @@ app.get(/^\/robots.txt$/, function ( req, res ) {
res.end( "User-agent: *\nDisallow: /\n" ); res.end( "User-agent: *\nDisallow: /\n" );
}); });
var handleRequests = function() {
// Call the next request on the queue
if (requestQueue.length) {
requestQueue[0]();
}
};
function handleRequest(req, res, tex) { function handleRequest(req, res, tex) {
// do the backend request // do the backend request
var query = new Buffer(querystring.stringify({tex:tex})), var reqbody = new Buffer(querystring.stringify({tex: tex})),
options = { options = {
hostname: 'localhost',
port: backendPort.toString(),
path: '/',
method: 'POST', method: 'POST',
uri: 'http://localhost:' + backendPort.toString() + '/',
body: reqbody,
// Work around https://github.com/ariya/phantomjs/issues/11421 by
// setting explicit upper-case headers (request sends them lowercase
// by default) and manually encoding the body.
headers: { headers: {
'Content-Length': query.length, 'Content-Length': reqbody.length,
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded'
'Connection': 'close'
}, },
agent: false timeout: 2000
}; };
var chunks = []; request(options, function (err, response, body) {
//console.log(options); body = new Buffer(body);
var httpreq = http.request(options, function(httpres) { if (err || response.statusCode !== 200) {
httpres.on('data', function(chunk) { var errBuf;
chunks.push(chunk); if (err) {
errBuf = new Buffer(JSON.stringify({
tex: tex,
log: err.toString(),
success: false
}));
} else {
errBuf = body;
}
res.writeHead(500,
{
'Content-Type': 'application/json',
'Content-Length': errBuf.length
}); });
httpres.on('end', function() { res.end(errBuf);
var buf = Buffer.concat(chunks); // don't retry the request
requestQueue.shift();
startBackend();
return handleRequests();
}
res.writeHead(200, res.writeHead(200,
{ {
'Content-type': 'application/json', 'Content-Type': 'application/json',
'Content-length': buf.length 'Content-length': body.length
}); });
res.write(buf); res.end(body);
res.end();
requestQueue.shift(); requestQueue.shift();
handleRequests(); handleRequests();
}); });
});
httpreq.on('error', function(err) {
console.log('error', err.toString());
res.writeHead(500);
return res.end(JSON.stringify({error: "Backend error: " + err.toString()}));
});
httpreq.end(query);
} }
handleRequests = function() {
// Call the next request on the queue
if (!backendStarting && requestQueue.length) {
requestQueue[0]();
}
};
app.post(/^\/$/, function ( req, res ) { app.post(/^\/$/, function ( req, res ) {
// First some rudimentary input validation // First some rudimentary input validation
if (!req.body.tex) { if (!req.body.tex) {

View file

@ -4,6 +4,7 @@
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"querystring": "0.x.x", "querystring": "0.x.x",
"express": "2.5.x" "express": "2.5.x",
"request": "2.x.x"
} }
} }