diff --git a/support/aphlict/server/aphlict_server.js b/support/aphlict/server/aphlict_server.js index 831437f76..d2594c720 100644 --- a/support/aphlict/server/aphlict_server.js +++ b/support/aphlict/server/aphlict_server.js @@ -1,245 +1,243 @@ /** * Notification server. Launch with: * * sudo node aphlict_server.js --user=aphlict * * You can also specify `port`, `admin`, `host` and `log`. */ var JX = require('./lib/javelin').JX; JX.require('lib/AphlictFlashPolicyServer', __dirname); JX.require('lib/AphlictListenerList', __dirname); JX.require('lib/AphlictLog', __dirname); var debug = new JX.AphlictLog() .addConsole(console); var clients = new JX.AphlictListenerList(); var config = parse_command_line_arguments(process.argv); if (config.logfile) { debug.addLogfile(config.logfile); } function parse_command_line_arguments(argv) { var config = { port: 22280, admin: 22281, host: '127.0.0.1', user: null, log: '/var/log/aphlict.log' }; for (var ii = 2; ii < argv.length; ii++) { var arg = argv[ii]; var matches = arg.match(/^--([^=]+)=(.*)$/); if (!matches) { throw new Error("Unknown argument '" + arg + "'!"); } if (!(matches[1] in config)) { throw new Error("Unknown argument '" + matches[1] + "'!"); } config[matches[1]] = matches[2]; } config.port = parseInt(config.port, 10); config.admin = parseInt(config.admin, 10); return config; } if (process.getuid() !== 0) { console.log( "ERROR: " + "This server must be run as root because it needs to bind to privileged " + "port 843 to start a Flash policy server. It will downgrade to run as a " + "less-privileged user after binding if you pass a user in the command " + "line arguments with '--user=alincoln'."); process.exit(1); } var net = require('net'); var http = require('http'); -var url = require('url'); process.on('uncaughtException', function(err) { - debug.log("\n<<< UNCAUGHT EXCEPTION! >>>\n" + err.stack); + debug.log('\n<<< UNCAUGHT EXCEPTION! >>>\n' + err.stack); process.exit(1); }); var flash_server = new JX.AphlictFlashPolicyServer() .setDebugLog(debug) .setAccessPort(config.port) .start(); var send_server = net.createServer(function(socket) { var listener = clients.addListener(socket); debug.log('<%s> Connected from %s', listener.getDescription(), socket.remoteAddress); var buffer = new Buffer([]); var length = 0; socket.on('data', function(data) { buffer = Buffer.concat([buffer, new Buffer(data)]); while (buffer.length) { if (!length) { length = buffer.readUInt16BE(0); buffer = buffer.slice(2); } if (buffer.length < length) { // We need to wait for the rest of the data. return; } var message; try { message = JSON.parse(buffer.toString('utf8', 0, length)); } catch (err) { debug.log('<%s> Received invalid data.', listener.getDescription()); continue; } finally { buffer = buffer.slice(length); length = 0; } debug.log('<%s> Received data: %s', listener.getDescription(), JSON.stringify(message)); switch (message.command) { case 'subscribe': debug.log( '<%s> Subscribed to: %s', listener.getDescription(), JSON.stringify(message.data)); listener.subscribe(message.data); break; case 'unsubscribe': debug.log( '<%s> Unsubscribed from: %s', listener.getDescription(), JSON.stringify(message.data)); listener.unsubscribe(message.data); break; default: debug.log(' Unrecognized command.', listener.getDescription()); } } }); socket.on('close', function() { clients.removeListener(listener); debug.log('<%s> Disconnected', listener.getDescription()); }); socket.on('timeout', function() { debug.log('<%s> Timed Out', listener.getDescription()); }); socket.on('end', function() { debug.log('<%s> Ended Connection', listener.getDescription()); }); socket.on('error', function(e) { debug.log('<%s> Error: %s', listener.getDescription(), e); }); }).listen(config.port); var messages_out = 0; var messages_in = 0; var start_time = new Date().getTime(); var receive_server = http.createServer(function(request, response) { // Publishing a notification. if (request.method == 'POST') { var body = ''; request.on('data', function(data) { body += data; }); request.on('end', function() { try { var msg = JSON.parse(body); debug.log('notification: ' + JSON.stringify(msg)); ++messages_in; transmit(msg); response.writeHead(200, {'Content-Type': 'text/plain'}); } catch (err) { response.statusCode = 400; response.write('400 Bad Request'); } finally { response.end(); } }); } else if (request.url == '/status/') { - request.on('data', function(data) { + request.on('data', function() { // We just ignore the request data, but newer versions of Node don't // get to 'end' if we don't process the data. See T2953. }); request.on('end', function() { var status = { 'uptime': (new Date().getTime() - start_time), 'clients.active': clients.getActiveListenerCount(), 'clients.total': clients.getTotalListenerCount(), 'messages.in': messages_in, 'messages.out': messages_out, 'log': config.log, 'version': 6 }; response.writeHead(200, {'Content-Type': 'text/plain'}); response.write(JSON.stringify(status)); response.end(); }); } else { response.statusCode = 400; response.write('400 Bad Request'); response.end(); } - }).listen(config.admin, config.host); function transmit(msg) { var listeners = clients.getListeners().filter(function(client) { return client.isSubscribedToAny(msg.subscribers); }); for (var i = 0; i < listeners.length; i++) { var listener = listeners[i]; try { listener.writeMessage(msg); ++messages_out; debug.log('<%s> Wrote Message', listener.getDescription()); } catch (error) { clients.removeListener(listener); debug.log('<%s> Write Error: %s', listener.getDescription(), error); } } } // If we're configured to drop permissions, get rid of them now that we've // bound to the ports we need and opened logfiles. if (config.user) { process.setuid(config.user); } debug.log('Started Server (PID %d)', process.pid); diff --git a/support/aphlict/server/lib/AphlictFlashPolicyServer.js b/support/aphlict/server/lib/AphlictFlashPolicyServer.js index 8651d643a..4c6ebcaab 100644 --- a/support/aphlict/server/lib/AphlictFlashPolicyServer.js +++ b/support/aphlict/server/lib/AphlictFlashPolicyServer.js @@ -1,68 +1,68 @@ var JX = require('javelin').JX; var net = require('net'); /** * Server which handles cross-domain policy requests for Flash. * * var server = new AphlictFlashPolicyServer() * .setAccessPort(9999) * .start(); */ JX.install('AphlictFlashPolicyServer', { members: { _server: null, _port: 843, _accessPort: null, _debug: null, setDebugLog: function(log) { this._debug = log; return this; }, setAccessPort: function(port) { this._accessPort = port; return this; }, start: function() { this._server = net.createServer(JX.bind(this, this._didConnect)); this._server.listen(this._port); return this; }, _didConnect: function(socket) { this._log(' Policy Request From %s', socket.remoteAddress); socket.on('error', JX.bind(this, this._didSocketError, socket)); socket.write(this._getFlashPolicyResponse()); socket.end(); }, _didSocketError: function(socket, error) { this._log(' Socket Error: %s', error); }, - _log: function(pattern) { + _log: function() { this._debug && this._debug.log.apply(this._debug, arguments); }, _getFlashPolicyResponse: function() { var policy = [ '', '', '', '', '' ]; - return policy.join("\n") + "\0"; + return policy.join('\n') + '\0'; } } }); diff --git a/support/aphlict/server/lib/AphlictLog.js b/support/aphlict/server/lib/AphlictLog.js index 259c03fad..73b903119 100644 --- a/support/aphlict/server/lib/AphlictLog.js +++ b/support/aphlict/server/lib/AphlictLog.js @@ -1,52 +1,52 @@ var JX = require('javelin').JX; var fs = require('fs'); var util = require('util'); JX.install('AphlictLog', { construct: function() { this._writeToLogs = []; this._writeToConsoles = []; }, members: { _writeToConsoles: null, _writeToLogs: null, addLogfile: function(path) { var options = { flags: 'a', encoding: 'utf8', mode: 066 }; var logfile = fs.createWriteSteam(path, options); this._writeToLogs.push(logfile); return this; }, addConsole: function(console) { this._writeToConsoles.push(console); return this; }, - log: function(pattern) { + log: function() { var str = util.format.apply(null, arguments); var date = new Date().toLocaleString(); str = '[' + date + '] ' + str; var ii; for (ii = 0; ii < this._writeToConsoles.length; ii++) { this._writeToConsoles[ii].log(str); } for (ii = 0; ii < this._writeToLogs.length; ii++) { - this._writeToLogs[ii].write(str + "\n"); + this._writeToLogs[ii].write(str + '\n'); } } } }); diff --git a/webroot/rsrc/js/application/differential/behavior-comment-jump.js b/webroot/rsrc/js/application/differential/behavior-comment-jump.js index d8aa728e0..53d43fd05 100644 --- a/webroot/rsrc/js/application/differential/behavior-comment-jump.js +++ b/webroot/rsrc/js/application/differential/behavior-comment-jump.js @@ -1,32 +1,32 @@ /** * @provides javelin-behavior-differential-comment-jump * @requires javelin-behavior * javelin-stratcom * javelin-dom */ JX.behavior('differential-comment-jump', function() { function handle_jump(offset) { - return (function(e) { + return function(e) { var parent = JX.$('differential-review-stage'); var clicked = e.getNode('differential-inline-comment'); var inlines = JX.DOM.scry(parent, 'div', 'differential-inline-comment'); var jumpto = null; for (var ii = 0; ii < inlines.length; ii++) { if (inlines[ii] == clicked) { jumpto = inlines[(ii + offset + inlines.length) % inlines.length]; break; } } JX.Stratcom.invoke('differential-toggle-file-request', null, { element: jumpto }); JX.DOM.scrollTo(jumpto); e.kill(); - }); + }; } JX.Stratcom.listen('click', 'differential-inline-prev', handle_jump(-1)); JX.Stratcom.listen('click', 'differential-inline-next', handle_jump(+1)); }); diff --git a/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js b/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js index 97359be31..757659121 100644 --- a/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js +++ b/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js @@ -1,182 +1,182 @@ /** * @provides javelin-behavior-phabricator-remarkup-assist * @requires javelin-behavior * javelin-stratcom * javelin-dom * phabricator-phtize * phabricator-textareautils * javelin-workflow * javelin-vector */ JX.behavior('phabricator-remarkup-assist', function(config) { var pht = JX.phtize(config.pht); var edit_mode = 'normal'; var edit_root = null; function set_edit_mode(root, mode) { if (mode == edit_mode) { return; } // First, disable any active mode. if (edit_root) { if (edit_mode == 'fa-arrows-alt') { JX.DOM.alterClass(edit_root, 'remarkup-control-fullscreen-mode', false); JX.DOM.alterClass(document.body, 'remarkup-fullscreen-mode', false); } JX.DOM.find(edit_root, 'textarea').style.height = ''; } edit_root = root; edit_mode = mode; // Now, apply the new mode. if (mode == 'fa-arrows-alt') { JX.DOM.alterClass(edit_root, 'remarkup-control-fullscreen-mode', true); JX.DOM.alterClass(document.body, 'remarkup-fullscreen-mode', true); resizearea(); } JX.DOM.focus(JX.DOM.find(edit_root, 'textarea')); } function resizearea() { if (!edit_root) { return; } if (edit_mode != 'fa-arrows-alt') { return; } // In Firefox, a textarea with position "absolute" or "fixed", anchored // "top" and "bottom", and height "auto" renders as two lines high. Force // it to the correct height with Javascript. var area = JX.DOM.find(edit_root, 'textarea'); var v = JX.Vector.getViewport(); v.x = null; v.y -= 26; v.setDim(area); } JX.Stratcom.listen('resize', null, resizearea); JX.Stratcom.listen('keydown', null, function(e) { if (e.getSpecialKey() != 'esc') { return; } if (edit_mode != 'fa-arrows-alt') { return; } e.kill(); set_edit_mode(edit_root, 'normal'); }); function update(area, l, m, r) { // Replace the selection with the entire assisted text. JX.TextAreaUtils.setSelectionText(area, l + m + r); // Now, select just the middle part. For instance, if the user clicked // "B" to create bold text, we insert '**bold**' but just select the word // "bold" so if they type stuff they'll be editing the bold text. var range = JX.TextAreaUtils.getSelectionRange(area); JX.TextAreaUtils.setSelectionRange( area, range.start + l.length, range.start + l.length + m.length); } function assist(area, action, root) { // If the user has some text selected, we'll try to use that (for example, // if they have a word selected and want to bold it). Otherwise we'll insert // generic text. var sel = JX.TextAreaUtils.getSelectionText(area); var r = JX.TextAreaUtils.getSelectionRange(area); switch (action) { case 'fa-bold': update(area, '**', sel || pht('bold text'), '**'); break; case 'fa-italic': update(area, '//', sel || pht('italic text'), '//'); break; case 'fa-link': var name = pht('name'); if (/^https?:/i.test(sel)) { update(area, '[[ ' + sel + ' | ', name, ' ]]'); } else { update(area, '[[ ', pht('URL'), ' | ' + (sel || name) + ' ]]'); } break; case 'fa-text-width': update(area, '`', sel || pht('monospaced text'), '`'); break; case 'fa-list-ul': case 'fa-list-ol': var ch = (action == 'fa-list-ol') ? ' # ' : ' - '; if (sel) { sel = sel.split('\n'); } else { sel = [pht('List Item')]; } sel = sel.join('\n' + ch); update(area, ((r.start === 0) ? '' : '\n\n') + ch, sel, '\n\n'); break; case 'fa-code': sel = sel || 'foreach ($list as $item) {\n work_miracles($item);\n}'; - var prefix = (r.start === 0) ? '' : '\n'; - update(area, prefix + '```\n', sel, '\n```'); + var code_prefix = (r.start === 0) ? '' : '\n'; + update(area, code_prefix + '```\n', sel, '\n```'); break; case 'fa-table': - var prefix = (r.start === 0 ? '' : '\n\n'); - update(area, prefix + '| ', sel || pht('data'), ' |'); + var table_prefix = (r.start === 0 ? '' : '\n\n'); + update(area, table_prefix + '| ', sel || pht('data'), ' |'); break; case 'fa-meh-o': new JX.Workflow('/macro/meme/create/') .setHandler(function(response) { update( area, '', sel, (r.start === 0 ? '' : '\n\n') + response.text + '\n\n'); }) .start(); break; case 'fa-cloud-upload': new JX.Workflow('/file/uploaddialog/').start(); break; case 'fa-arrows-alt': if (edit_mode == 'fa-arrows-alt') { set_edit_mode(root, 'normal'); } else { set_edit_mode(root, 'fa-arrows-alt'); } break; } } JX.Stratcom.listen( ['click'], 'remarkup-assist', function(e) { var data = e.getNodeData('remarkup-assist'); if (!data.action) { return; } e.kill(); var root = e.getNode('remarkup-assist-control'); var area = JX.DOM.find(root, 'textarea'); assist(area, data.action, root); }); });