started work on message bus diags

This commit is contained in:
Sam Saffron 2013-02-15 19:23:40 +11:00
parent 89ff51e108
commit eb188c57e8
12 changed files with 38210 additions and 13 deletions

View File

@ -3,12 +3,7 @@ MessageBus.site_id_lookup do
end
MessageBus.user_id_lookup do |env|
request = Rack::Request.new(env)
auth_token = request.cookies["_t"]
user = nil
if auth_token && auth_token.length == 32
user = User.where(auth_token: auth_token).first
end
user = CurrentUser.lookup_from_env(env)
user.id if user
end
@ -25,3 +20,14 @@ MessageBus.redis_config = YAML::load(File.open("#{Rails.root}/config/redis.yml")
MessageBus.long_polling_enabled = SiteSetting.enable_long_polling
MessageBus.long_polling_interval = SiteSetting.long_polling_interval
MessageBus.is_admin_lookup do |env|
user = CurrentUser.lookup_from_env(env)
if user && user.admin
true
else
false
end
end
MessageBus.cache_assets = !Rails.env.development?

View File

@ -1,5 +1,16 @@
module CurrentUser
def self.lookup_from_env(env)
request = Rack::Request.new(env)
auth_token = request.cookies["_t"]
user = nil
if auth_token && auth_token.length == 32
user = User.where(auth_token: auth_token).first
end
return user
end
def current_user
return @current_user if @current_user || @not_logged_in

View File

@ -0,0 +1,7 @@
<header>
<h2>Message Bus Diagnostics<h2>
</header>
<div>
{{outlet}}
</div>

View File

@ -0,0 +1,48 @@
window.App = Ember.Application.createWithMixins({
start: function(){
MessageBus.start();
}
});
window.App.start();
App.IndexRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('content', App.IndexModel.create());
}
});
App.IndexView = Ember.View.extend({
});
App.IndexModel = Ember.Object.extend({
disabled: function(){
return this.get("discovering") ? "disabled" : null;
}.property("discovering"),
discover: function(){
var _this = this;
this.set("discovering", true);
Ember.run.later(function(){
_this.set("discovering", false);
}, 20 * 1000);
$.post("/message-bus/_diagnostics/discover");
MessageBus.subscribe("/process-discovery", function(data){
console.log(data);
});
}
});
App.IndexController = Ember.ObjectController.extend({
discover: function(){
this.get("content").discover();
}
});

26480
vendor/gems/message_bus/assets/ember.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<button {{action discover}} {{bindAttr disabled="disabled"}}>Discover Processes</button>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,136 @@
window.MessageBus = (function() {
var callbacks, clientId, failCount, interval, isHidden, queue, responseCallbacks, uniqueId;
uniqueId = function() {
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r, v;
r = Math.random() * 16 | 0;
v = c === 'x' ? r : r & 0x3 | 0x8;
return v.toString(16);
});
};
clientId = uniqueId();
responseCallbacks = {};
callbacks = [];
queue = [];
interval = null;
failCount = 0;
isHidden = function() {
if (document.hidden !== void 0) {
return document.hidden;
} else if (document.webkitHidden !== void 0) {
return document.webkitHidden;
} else if (document.msHidden !== void 0) {
return document.msHidden;
} else if (document.mozHidden !== void 0) {
return document.mozHidden;
} else {
return !document.hasFocus;
}
};
return {
enableLongPolling: true,
callbackInterval: 60000,
maxPollInterval: 3 * 60 * 1000,
callbacks: callbacks,
clientId: clientId,
stop: false,
start: function(opts) {
var poll,
_this = this;
if (opts == null) {
opts = {};
}
poll = function() {
var data, gotData;
if (callbacks.length === 0) {
setTimeout(poll, 500);
return;
}
data = {};
callbacks.each(function(c) {
return data[c.channel] = c.last_id === void 0 ? -1 : c.last_id;
});
gotData = false;
return _this.longPoll = $.ajax("/message-bus/" + clientId + "/poll?" + (isHidden() || !_this.enableLongPolling ? "dlp=t" : ""), {
data: data,
cache: false,
dataType: 'json',
type: 'POST',
headers: {
'X-SILENCE-LOGGER': 'true'
},
success: function(messages) {
failCount = 0;
return messages.each(function(message) {
gotData = true;
return callbacks.each(function(callback) {
if (callback.channel === message.channel) {
callback.last_id = message.message_id;
callback.func(message.data);
}
if (message["channel"] === "/__status") {
if (message.data[callback.channel] !== void 0) {
callback.last_id = message.data[callback.channel];
}
}
});
});
},
error: failCount += 1,
complete: function() {
if (gotData) {
setTimeout(poll, 100);
} else {
interval = _this.callbackInterval;
if (failCount > 2) {
interval = interval * failCount;
} else if (isHidden()) {
interval = interval * 4;
}
if (interval > _this.maxPollInterval) {
interval = _this.maxPollInterval;
}
setTimeout(poll, interval);
}
_this.longPoll = null;
}
});
};
poll();
},
subscribe: function(channel, func, lastId) {
callbacks.push({
channel: channel,
func: func,
last_id: lastId
});
if (this.longPoll) {
return this.longPoll.abort();
}
},
unsubscribe: function(channel) {
var glob;
if (channel.endsWith("*")) {
channel = channel.substr(0, channel.length - 1);
glob = true;
}
callbacks = callbacks.filter(function(callback) {
if (glob) {
return callback.channel.substr(0, channel.length) !== channel;
} else {
return callback.channel !== channel;
}
});
if (this.longPoll) {
return this.longPoll.abort();
}
}
};
})();

View File

@ -20,6 +20,18 @@ end
module MessageBus; end
module MessageBus::Implementation
def cache_assets=(val)
@cache_assets = val
end
def cache_assets
if defined? @cache_assets
@cache_assets
else
true
end
end
def logger=(logger)
@logger = logger
end

View File

@ -5,31 +5,86 @@ class MessageBus::Rack::Diagnostics
@app = app
end
def js_asset(name)
return generate_script_tag(name) unless MessageBus.cache_assets
@@asset_cache ||= {}
@@asset_cache[name] ||= generate_script_tag(name)
@@asset_cache[name]
end
def generate_script_tag(name)
"<script src='/message-bus/_diagnostics/assets/#{name}?#{file_hash(name)}' type='text/javascript'></script>"
end
def file_hash(asset)
require 'digest/sha1'
Digest::SHA1.hexdigest(asset_contents(asset))
end
def asset_contents(asset)
File.open(asset_path(asset)).read
end
def asset_path(asset)
File.expand_path("../../../../assets/#{asset}", __FILE__)
end
def index
html = <<HTML
<!DOCTYPE html>
<html>
<head></head>
<head>
</head>
<body>
<h2>Message Bus Diags</h2>
<div id="app"></div>
#{js_asset "jquery-1.8.2.js"}
#{js_asset "handlebars-1.0.rc.2.js"}
#{js_asset "ember.js"}
#{js_asset "message-bus.js"}
#{js_asset "application.handlebars"}
#{js_asset "index.handlebars"}
#{js_asset "application.js"}
</body>
</html>
HTML
return [200, {"content-type" => "text/html;"}, html]
return [200, {"content-type" => "text/html;"}, [html]]
end
def translate_handlebars(name, content)
"Ember.TEMPLATES['#{name}'] = Ember.Handlebars.compile(#{indent(content).inspect});"
end
# from ember-rails
def indent(string)
string.gsub(/$(.)/m, "\\1 ").strip
end
def call(env)
return @app.call(env) unless env['PATH_INFO'].start_with? '/message-bus/_diagnostics'
route = env['PATH_INFO'].split('/message_bus/_diagnostics')[1]
route = env['PATH_INFO'].split('/message-bus/_diagnostics')[1]
if MessageBus.is_admin_lookup.nil? || !MessageBus.is_admin_lookup.call
return [403, {}, ["not allowed"]]
if MessageBus.is_admin_lookup.nil? || !MessageBus.is_admin_lookup.call(env)
return [403, {}, ['not allowed']]
end
return index unless route
if route == 'discover'
MessageBus.publish('/discover', {user_id: MessageBus() })
end
asset = route.split('/assets/')[1]
if asset && !asset !~ /\//
content = asset_contents(asset)
split = asset.split('.')
if split[1] == 'handlebars'
content = translate_handlebars(split[0],content)
end
return [200, {'content-type' => 'text/javascript;'}, [content]]
end
return [404, {}, ["not found"]]
return [404, {}, ['not found']]
end
end

View File

@ -122,6 +122,14 @@ describe MessageBus::Rack::Middleware do
get "/message-bus/_diagnostics"
last_response.status.should == 200
end
it "should get the script it asks for" do
MessageBus.stub(:is_admin_lookup).and_return(lambda{ true })
get "/message-bus/_diagnostics/assets/message-bus.js"
last_response.status.should == 200
last_response.content_type.should == "text/javascript;"
end
end
describe "polling" do