UNPKG

aq-web-front

Version:

A compilation framework to allow coding web frontends in a modern style.

175 lines (165 loc) 5.72 kB
var udp = require('dgram'); var tcp = require('net'); var concat = require('concat-stream'); var path = require('path'); exports.start = start; exports.stop = stop; exports.compile = compile; /** * Starts a compiler server if none is available. * Returns the available (or newly started server port) through callback **/ function start(callback) { searchForExisting(function(port) { if (port) { callback(port, false); } else { var fork = require('./fork'); var server = tcp.createServer({ allowHalfOpen:true }, function(client) { client.pipe(concat(function(data) { if (data.length == 3 && data[0] == 0) { client.end(); closeAll(); } else { var job; try { job = JSON.parse(data); } catch (e) { client.end(); return; } client.on('error', function(err) { console.warn(err.toString()); }); var compiler = fork.openCompiler(job.compilerPath); if (job.inOpt) { compiler.send(job, client); } else { client.end(); } } })); }); var announcer; server.listen(function() { var port = server.address().port; announcer = udp.createSocket({ type: 'udp4', reuseAddr: true }); announcer.on('error', bindAnnoucer); var announcerPort = 15301; function bindAnnoucer() { if (announcerPort <= 15304) { announcer.bind(announcerPort); announcerPort++; } else { console.error('UDP port 15301-15304 is all occupied please keep at least one available'); announcer = null; closeAll(); server.on('close', function() { process.exit(2); }); } } bindAnnoucer(); var sendPack = new Buffer([15,30,19,74,7,0,0]); sendPack.writeUInt16LE(port, 5); announcer.on('message', function(msg, rinfo) { announcer.send(sendPack, 0, 7, rinfo.port, rinfo.address); }); callback(port, true); }); server.on('error', function() { console.error('JS compiler server failed to start'); }); function closeAll() { fork.close(); if (announcer) { announcer.close(); } server.close(); } } }); } /** * Emit stop signal to existing compiler server. * Callback will be called when server ends or 10 seconds timeout. */ function stop(callback) { searchForExisting(function(port) { if (port) { var client = tcp.connect({port:port}, function() { client.write(new Buffer([0,0,0])); client.end(); }); client.on('close', function() { callback(); }); } else { callback(); } }); } /** * Send compile job to a new or existing server */ function compile(compilerPath, inOpt, callback) { start(function(port) { var client = tcp.connect({port:port,allowHalfOpen:true}, function() { client.end(new Buffer(JSON.stringify({ compilerPath: compilerPath, inOpt: inOpt }))); if (callback) { client.on('close', function() { callback(); }); } }); }); } //= Internal functions function searchForExisting(callback) { var sock = udp.createSocket({ type: 'udp4', reuseAddr: true }); sock.bind(); sock.on('message', function(msg, rinfo) { if (msg.length == 7 && msg[0] == 15 && msg[1] == 30 && msg[2] == 19 && msg[3] == 74 && msg[4] == 7) { closeAll(); callback(msg.readUInt16LE(5)); } }); sock.send(new Buffer([1]), 0, 1, 15301, '127.0.0.1'); sock.send(new Buffer([1]), 0, 1, 15302, '127.0.0.1'); sock.send(new Buffer([1]), 0, 1, 15303, '127.0.0.1'); sock.send(new Buffer([1]), 0, 1, 15304, '127.0.0.1'); sock.unref(); var sendDelay = setTimeout(function() { sendDelay = false; sock.send(new Buffer([1]), 0, 1, 15301, '127.0.0.1'); sock.send(new Buffer([1]), 0, 1, 15302, '127.0.0.1'); sock.send(new Buffer([1]), 0, 1, 15303, '127.0.0.1'); sock.send(new Buffer([1]), 0, 1, 15304, '127.0.0.1'); }, 200); var timeout = setTimeout(function() { closeAll(); callback(false); }, 400); function closeAll() { clearTimeout(timeout); if (sendDelay) clearTimeout(sendDelay); sock.close(); } }