Fixes T6559. No more flash, use Websockets. This is less aggressive than the earlier version, and retains more server logic.
- Support "wss".
- Make the client work.
- Remove "notification.user" entirely.
- Seems ok?
Differential D11143
Rewrite Aphlict to use Websockets epriestley on Jan 2 2015, 7:59 AM. Authored by Tags None Referenced Files
Subscribers
Details
Fixes T6559. No more flash, use Websockets. This is less aggressive than the earlier version, and retains more server logic.
In Safari, Firefox and Chrome, saw the browsers connect. Made a bunch of comments/updates and saw notifications. Notable holes in the test plan:
Diff Detail
Event TimelineComment Actions At least tentatively, I'd like to keep Flash around, and support WebSockets in addition to Flash. The underlying Flash protocol (i.e., really basic JSON with no weird websocket handshaking) is better for non-browser clients, and Flash has some advantages and desirable characteristics when multiple browser windows are open simultaneously. I'm also much more interested in upstreaming this if the websocket implementation is <1K lines (and, ideally, like 300) than if it's, say, socket.io. Provided the websocket implementation isn't an enormously gigantic dependency I'm open to upstreaming support, though. Comment Actions My thinking along those lines were as follows:
Comment Actions
This uses the old, more insane version of the protocol with Key1 and Key2 headers, and doesn't seem to work in modern browsers. I was able to get this working pretty easily, though: Comment Actions
Comment Actions
Comment Actions The "notifications are too fast" thing seems like a problem that you may want to fix before submitting / within a few hours of submitting. Also, does this mean there's a bunch of browsers we no longer support? (Yay in my book... :D) Otherwise though... Comment Actions This looks good to me. One potential issue (I think) is that users will blindly update their install and wonder why Aphlict no longer works. We could feasibly add a setup check that checks whether ws is installed, but I'm not sure if this would provide much value because we don't really know on which host Aphlict is running (it doesn't have to be on the web app host). I think that the best that we can do here is add a try/catch to the require('ws') call and provide installation instructions if the package is missing. We could possibly also add some more information to PhabricatorExtraConfigSetupCheck to say "Hey, you have `notification.user
Comment Actions This looks good to me. One potential issue (I think) is that users will blindly update their install and wonder why Aphlict no longer works. We could feasibly add a setup check that checks whether ws is installed, but I'm not sure if this would provide much value because we don't really know on which host Aphlict is running (it doesn't have to be on the web app host). I think that the best that we can do here is add a try/catch to the require('ws') call and provide installation instructions if the package is missing. We could possibly also add some more information to PhabricatorExtraConfigSetupCheck to say "Hey, you have notification.user set... you should unset this and also install ws. This won't provide any value for users who run the Flash-based Aphlict server as root. Something else worth mentioning (although I'm not sure if/what we want to do with this) is that it is possible to route the WebSockets traffic through nginx. In my testing, I was using the following nginx configuration: /etc/nginx/conf.d/connection_upgrade.conf map $http_upgrade $connection_upgrade { default upgrade; '' close; } /etc/nginx/conf.d/websockets.conf upstream websockets { ip_hash; server 127.0.0.1:22280; } /etc/nginx/sites-enabled/phabricator.local.conf server { listen *:80; server_name phabricator.local; root /usr/src/phabricator/webroot; index index.php; location /index.php { include /etc/nginx/fastcgi_params; fastcgi_pass php_pool; fastcgi_index index.php; } location = /favicon.ico { try_files $uri =204; } location /ws/ { proxy_pass http://websockets; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 999999999; } location / { root /usr/src/phabricator/webroot; index index.html index.htm index.php; rewrite ^/(.*)$ /index.php?__path__=/$1 last; } } I think that this solution is nice because we should be able to terminate SSL at the nginx layer. It is also a step in the right direction in terms of scaling the Aphlict server. On the downside, it is a bit more advanced and could be difficult to support (also, I have no idea about Apache). Comment Actions Just some personal experience with ws vs. wss: Because of this we've enforced wss everywhere (with a proxy/lb like nginx or similar in front). WebSockets should not be used in a mixed content environment; that is, you shouldn't open a non-secure WebSocket connection from a page loaded using HTTPS or vice-versa. In fact, some browsers explicitly forbid this, including Firefox 8 and later. Comment Actions Yeah, let me sneak in a fix before this for the self-notifications. I'm just going to try this rule:
That will get this case wrong:
I think I may also need to fix T6713 before this can land, since it's pretty bad locally. Comment Actions I think there miiight be an argument for trying to install ws ourselves if it's missing, but for now I'll just try/catch and we can see how much of a headache that causes. Comment Actions
Comment Actions A couple of other notes:
Comment Actions I just applied this on my dev install and noticed an issue. It seems that with the default value for notification.client-uri and notification.server-uri, the Aphlict server will only listen for WebSocket connections on localhost. I was able to fix this by listening on 0.0.0.0 instead. Comment Actions I just applied this on my dev install and noticed an issue. It seems that with the default value for notification.client-uri and notification.server-uri, the Aphlict server will only listen for WebSocket connections on localhost. I was able to fix this by listening on 0.0.0.0 instead. +1 to removing both. Comment Actions
Comment Actions
Comment Actions Looks like its not too bad to tell if a given tab is the focused tab? (So silence stuff on focused tab...) http://www.thefutureoftheweb.com/blog/detect-browser-window-focus Comment Actions eh, maybe that's a more complicated mess than I thought. See http://greensock.com/forums/topic/9059-cross-browser-to-detect-tab-or-window-is-active-so-animations-stay-in-sync-using-html5-visibility-api/ for a more modern, much crazier looking "solution" to knowing which tab has focus. Comment Actions
If no tab is focused (e.g., you have Phabricator open but Facebook is the active tab) we still want to play notification sounds (depending on user pref / product design choices) and send desktop notifications. I believe tabs lose focus when you switch to another application, as well. For example, if I have Phabricator open and then switch to email, the tab blurs. These events are useful for "pause a game the user is playing" but all tabs are blurred at the time when desktop notifications / sounds are most important (to alert the user to a background event). Comment Actions Oh, just for the bubble. The problem is we don't know which tab the notification came from. If we get a notification that T2 is updated, and T2 is in the current tab, we do want to show it if the notification came from a different tab. We also want to show it in open tabs which don't happen to be active. One possible fix is just to have each tab generate a random ID, and send it whenever the user does anything, and attach it to the notification. Then when a tab gets a notification back, it just checks if it was the original responsible tab. That will require a fair chunk of work, but seems like the only approach that doesn't involve a lot of race conditions, at last that I can come up with. Comment Actions There are definitely some other product behaviors we can refine here, too. A big one is that right now, you don't get a notification about something that you're looking at unless you're also subscribed to it. Fixing this isn't too tough but cascaded enough that I ripped it out of an early version of this diff. In general, this diff shouldn't actually change any behaviors, but I expect things will be faster and more reliable now, so any sketchy behaviors which previously went unnoticed by being slow/unreliable may be sucky/painful now. |