From 8033a697461d6b621d2d12b54f33e925dd5b21b0 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Thu, 5 Jun 2014 09:41:46 -0700 Subject: [PATCH] Catch errors that may occur whilst receiving data from the Aphlict server. Summary: Ref T4324. Currently, if the `AphlictMaster` receives dodgy data from the Aphlict server (invalid JSON, for example) then a syntax error will be thrown and the `AphlictMaster` will die. Instead, catch errors and raise a notification. Test Plan: {F163466} Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T4324 Differential Revision: https://secure.phabricator.com/D9380 --- support/aphlict/client/src/Aphlict.as | 4 ++ support/aphlict/client/src/AphlictMaster.as | 54 ++++++++++-------- .../aphlict/behavior-aphlict-listen.js | 51 +++++++++++------ webroot/rsrc/swf/aphlict.swf | Bin 5315 -> 5470 bytes 4 files changed, 65 insertions(+), 44 deletions(-) diff --git a/support/aphlict/client/src/Aphlict.as b/support/aphlict/client/src/Aphlict.as index d61ad04b0a..592bbd4e54 100644 --- a/support/aphlict/client/src/Aphlict.as +++ b/support/aphlict/client/src/Aphlict.as @@ -31,6 +31,10 @@ package { ExternalInterface.call('JX.Aphlict.didReceiveEvent', type, object); } + protected function error(error:Error):void { + this.externalInvoke('error', error.toString()); + } + protected function log(message:String):void { this.externalInvoke('log', message); } diff --git a/support/aphlict/client/src/AphlictMaster.as b/support/aphlict/client/src/AphlictMaster.as index 1991ab48bd..ee07fe53e6 100644 --- a/support/aphlict/client/src/AphlictMaster.as +++ b/support/aphlict/client/src/AphlictMaster.as @@ -131,34 +131,38 @@ package { } private function didReceiveSocket(event:Event):void { - var b:ByteArray = this.readBuffer; - this.socket.readBytes(b, b.length); + try { + var b:ByteArray = this.readBuffer; + this.socket.readBytes(b, b.length); - do { - b = this.readBuffer; - b.position = 0; + do { + b = this.readBuffer; + b.position = 0; - if (b.length <= 8) { - break; - } - - var msg_len:Number = parseInt(b.readUTFBytes(8), 10); - if (b.length >= msg_len + 8) { - var bytes:String = b.readUTFBytes(msg_len); - var data:Object = vegas.strings.JSON.deserialize(bytes); - var t:ByteArray = new ByteArray(); - t.writeBytes(b, msg_len + 8); - this.readBuffer = t; - - // Send the message to all clients. - for (var client:String in this.clients) { - this.log('Sending message to client: ' + client); - this.send.send(client, 'receiveMessage', data); + if (b.length <= 8) { + break; } - } else { - break; - } - } while (true); + + var msg_len:Number = parseInt(b.readUTFBytes(8), 10); + if (b.length >= msg_len + 8) { + var bytes:String = b.readUTFBytes(msg_len); + var data:Object = vegas.strings.JSON.deserialize(bytes); + var t:ByteArray = new ByteArray(); + t.writeBytes(b, msg_len + 8); + this.readBuffer = t; + + // Send the message to all clients. + for (var client:String in this.clients) { + this.log('Sending message to client: ' + client); + this.send.send(client, 'receiveMessage', data); + } + } else { + break; + } + } while (true); + } catch (err:Error) { + this.error(err); + } } } diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js index 5fc15968d1..0f40d2c13f 100644 --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js @@ -24,25 +24,39 @@ JX.behavior('aphlict-listen', function(config) { // Respond to a notification from the Aphlict notification server. We send // a request to Phabricator to get notification details. function onaphlictmessage(type, message) { - if (type == 'receive') { - var routable = new JX.Request('/notification/individual/', onnotification) - .addData({key: message.key}) - .getRoutable(); - - routable - .setType('notification') - .setPriority(250); - - JX.Router.getInstance().queue(routable); - } else if (__DEV__) { - if (config.debug) { - var details = message ? JX.JSON.stringify(message) : ''; - + switch (type) { + case 'error': new JX.Notification() - .setContent('(Aphlict) [' + type + '] ' + details) - .alterClassName('jx-notification-debug', true) + .setContent('(Aphlict) ' + message) + .alterClassName('jx-notification-error', true) .show(); - } + break; + + case 'receive': + var routable = new JX.Request( + '/notification/individual/', + onnotification); + + routable + .addData({key: message.key}) + .getRoutable(); + + routable + .setType('notification') + .setPriority(250); + + JX.Router.getInstance().queue(routable); + break; + + default: + if (__DEV__ && config.debug) { + var details = message ? JX.JSON.stringify(message) : ''; + + new JX.Notification() + .setContent('(Aphlict) [' + type + '] ' + details) + .alterClassName('jx-notification-debug', true) + .show(); + } } } @@ -63,8 +77,7 @@ JX.behavior('aphlict-listen', function(config) { // If the notification affected an object on this page, show a // permanent reload notification if we aren't already. - if ((response.primaryObjectPHID in config.pageObjects) && - !showing_reload) { + if ((response.primaryObjectPHID in config.pageObjects) && !showing_reload) { var reload = new JX.Notification() .setContent('Page updated, click to reload.') .alterClassName('jx-notification-alert', true) diff --git a/webroot/rsrc/swf/aphlict.swf b/webroot/rsrc/swf/aphlict.swf index cee18c7dc6ebe486fa90ea29721197e11431788a..c6ffcdbd32023f5bc68a472d77e1b32c547e73a2 100644 GIT binary patch literal 5470 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 VU9p<|TiVY5+s9my{{ySMFv?EqEmQyi