FEATURE: allow long polling to go to a different url

Added the site setting long_polling_base_url , this allows you
to farm long polling to a different server.

This setting is very important if a CDN is serving dynamic content.
This commit is contained in:
Sam 2014-10-24 13:38:00 +11:00
parent 1962563c31
commit aa9b3bb35a
8 changed files with 53 additions and 4 deletions

View file

@ -163,7 +163,7 @@ GEM
mime-types (~> 1.16)
treetop (~> 1.4.8)
memory_profiler (0.0.4)
message_bus (1.0.0)
message_bus (1.0.4)
eventmachine
rack (>= 1.1.3)
redis

View file

@ -2,7 +2,7 @@
Subscribes to user events on the message bus
**/
export default {
name: "subscribe-user-notifications",
name: 'subscribe-user-notifications',
after: 'message-bus',
initialize: function(container) {
var user = Discourse.User.current();
@ -13,14 +13,25 @@ export default {
var bus = Discourse.MessageBus;
bus.callbackInterval = siteSettings.anon_polling_interval;
bus.backgroundCallbackInterval = siteSettings.background_polling_interval;
bus.baseUrl = siteSettings.long_polling_base_url;
if (bus.baseUrl !== '/') {
// zepto compatible, 1 param only
bus.ajax = function(opts){
opts.headers = opts.headers || {};
opts.headers['X-Shared-Session-Key'] = $('meta[name=shared_session_key]').attr('content');
return $.ajax(opts);
};
} else {
bus.baseUrl = Discourse.getURL('/');
}
if (user) {
bus.callbackInterval = siteSettings.polling_interval;
bus.enableLongPolling = true;
bus.baseUrl = Discourse.getURL("/");
if (user.admin || user.moderator) {
bus.subscribe("/flagged_counts", function(data) {
bus.subscribe('/flagged_counts', function(data) {
user.set('site_flagged_posts_count', data.total);
});
}

View file

@ -11,6 +11,17 @@ module ApplicationHelper
include CanonicalURL::Helpers
include ConfigurableUrls
def shared_session_key
if SiteSetting.long_polling_base_url != '/'.freeze && current_user
sk = "shared_session_key"
return request.env[sk] if request.env[sk]
request.env[sk] = key = (session[sk] ||= SecureRandom.hex)
$redis.setex "#{sk}_#{key}", 7.days, current_user.id.to_s
key
end
end
def script(*args)
if SiteSetting.enable_cdn_js_debugging && GlobalSetting.cdn_url
tags = javascript_include_tag(*args, "crossorigin" => "anonymous")

View file

@ -10,6 +10,10 @@
<meta name="fragment" content="!">
<%- end %>
<%- if shared_session_key %>
<meta name="shared_session_key" content="<%= shared_session_key %>">
<%- end %>
<%= script "preload_store" %>
<%= script "locales/#{I18n.locale}" %>
<%= script "vendor" %>

View file

@ -2,6 +2,14 @@ MessageBus.site_id_lookup do
RailsMultisite::ConnectionManagement.current_db
end
MessageBus.extra_response_headers_lookup do |env|
{
"Access-Control-Allow-Origin" => Discourse.base_url,
"Access-Control-Allow-Methods" => "GET, POST",
"Access-Control-Allow-Headers" => "X-SILENCE-LOGGER, X-Shared-Session-Key"
}
end
MessageBus.user_id_lookup do |env|
user = CurrentUser.lookup_from_env(env)
user.id if user

View file

@ -698,6 +698,7 @@ en:
enable_private_messages: "Allow trust level 1 users to create private messages and reply to private messages"
enable_long_polling: "Message bus used for notification can use long polling"
long_polling_base_url: "Base URL used for long polling (when a CDN is serving dynamic content, be sure to set this to origin pull) eg: http://origin.site.com"
long_polling_interval: "Amount of time the server should wait before responding to clients when there is no data to send (logged on users only)"
polling_interval: "When not long polling, how often should logged on clients poll in milliseconds"
anon_polling_interval: "How often should anonymous clients poll in milliseconds"

View file

@ -616,6 +616,9 @@ developer:
client: true
default: true
long_polling_interval: 25000
long_polling_base_url:
client: true
default: '/'
background_polling_interval:
client: true
default: 60000

View file

@ -18,6 +18,17 @@ class Auth::DefaultCurrentUserProvider
def current_user
return @env[CURRENT_USER_KEY] if @env.key?(CURRENT_USER_KEY)
# bypass if we have the shared session header
if shared_key = @env['HTTP_X_SHARED_SESSION_KEY']
uid = $redis.get("shared_session_key_#{shared_key}")
user = nil
if uid
user = User.find_by(id: uid.to_i)
end
@env[CURRENT_USER_KEY] = user
return user
end
request = @request
auth_token = request.cookies[TOKEN_COOKIE]