Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Sync with SVN (we'll do a better job at this in the future)

  • Loading branch information...
commit 948b2abe7faade2e0797ced1aa0147defc65e5f3 1 parent 408da88
@maccman maccman authored
Showing with 198 additions and 82 deletions.
  1. +58 −1 README
  2. +44 −8 lib/juggernaut.rb
  3. +96 −73 media/juggernaut.js
View
59 README
@@ -165,7 +165,64 @@ You'll need to add the Rails IP to juggernaut.yml, like so:
:allowed_ips:
- 127.0.0.1
- 192.168.0.4 # IP of the Rails app
-
+
+===============================================
+Jquery
+===============================================
+
+To get Juggernaut working with Jquery (Prototype is used by default) follow the tutorial above with the following differences.
+
+>>Javascripts
+
+ You must have jquery.js (version 1.2.6 tested) and the jquery-json plugin (http://www.jdempster.com/wp-content/uploads/2007/08/jquery.json.js) in the /javascripts directory.
+
+ You need the jquerynaut.js file in the /javascripts/juggernaut directory (found in /lib in the media directory)
+
+
+>>The chat controller:
+
+ class ChatController < ApplicationController
+ def index
+ end
+
+ def send_data
+ render :juggernaut do |page|
+ page["#chat_data"].prepend "<li>#{h params[:chat_input]}</li>"
+ end
+ render :nothing => true
+ end
+
+ end
+
+
+>>The index.html.erb
+
+ <html>
+ <head>
+ <%= javascript_include_tag 'jquery', 'json', 'juggernaut/juggernaut', 'juggernaut/jquerynaut', 'juggernaut/swfobject' %>
+ <%= juggernaut %>
+ </head>
+ <body>
+ <form action="/chat/send_data" method="get">
+ <div style="margin:0;padding:0">
+ <input id="chat_input" name="chat_input" size="20" type="text" value="" />
+ <input name="commit" type="submit" value="Add" />
+ </form>
+
+ <script>
+ $(document).ready(function(){
+ $('form').submit(function(){
+ $.get('/chat/send_data', { chat_input: $('#chat_input').val() } )
+ return false;
+ })
+ })
+ </script>
+ <ul id="chat_data" style="list-style:none"></ul>
+ </body>
+ </html>
+
+
+
===============================================
Troubleshooting
===============================================
View
52 lib/juggernaut.rb
@@ -3,6 +3,7 @@
module Juggernaut
CONFIG = YAML::load(ERB.new(IO.read("#{RAILS_ROOT}/config/juggernaut_hosts.yml")).result).freeze
+ CR = "\0"
class << self
@@ -71,26 +72,61 @@ def remove_all_channels(channels)
}
send_data(fc)
end
+
+ def show_clients
+ fc = {
+ :command => :query,
+ :type => :show_clients
+ }
+ send_data(fc, true).flatten
+ end
+
+ def show_client(client_id)
+ fc = {
+ :command => :query,
+ :type => :show_client,
+ :client_id => client_id
+ }
+ send_data(fc, true).flatten[0]
+ end
+
+ def show_clients_for_channels(channels)
+ fc = {
+ :command => :query,
+ :type => :show_clients_for_channels,
+ :channels => channels
+ }
+ send_data(fc, true).flatten
+ end
+ alias show_clients_for_channel show_clients_for_channels
- def send_data(hash)
- hash[:channels] = hash[:channels].to_a if hash[:channels]
+ def send_data(hash, response = false)
+ hash[:channels] = hash[:channels].to_a if hash[:channels]
hash[:client_ids] = hash[:client_ids].to_a if hash[:client_ids]
-
- CONFIG[:hosts].select {|h| !h[:environment] or h[:environment] == ENV['RAILS_ENV'].to_sym }.each do |address|
+
+ res = []
+ hosts.each do |address|
begin
hash[:secret_key] = address[:secret_key] if address[:secret_key]
@socket = TCPSocket.new(address[:host], address[:port])
# the \0 is to mirror flash
- @socket.print(hash.to_json + "\0")
+ @socket.print(hash.to_json + CR)
@socket.flush
- # rescue => e
- # puts e
- # false
+ res << @socket.readline(CR) if response
ensure
@socket.close if @socket and !@socket.closed?
end
end
+ res.collect {|r| ActiveSupport::JSON.decode(r.chomp!(CR)) } if response
+ end
+
+ private
+
+ def hosts
+ CONFIG[:hosts].select {|h|
+ !h[:environment] or h[:environment].to_s == ENV['RAILS_ENV']
+ }
end
end
View
169 media/juggernaut.js
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2007 Alexander MacCaw
+Copyright (c) 2008 Alexander MacCaw
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -21,78 +21,71 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-if (typeof Prototype == 'undefined') throw("Juggernaut error. Prototype could not be found.");
-if (Prototype.Version < "1.6") throw("Juggernaut error. Prototype 1.6.0 is required.");
+function Juggernaut(options) {
+ this.is_connected = false,
+ this.attempting_to_reconnect = false
+ this.ever_been_connected = false
+ this.hasFirebug = "console" in window && "firebug" in window.console
+ this.options = options
+ this.bindToWindow();
+ }
-var Juggernaut = Class.create({
- is_connected: false,
- attempting_to_reconnect: false,
- ever_been_connected: false,
- hasFirebug: "console" in window && "firebug" in window.console,
+Juggernaut.fn = Juggernaut.prototype
- logger: function(msg) {
+Juggernaut.fn.logger = function(msg) {
if (this.options.debug) {
msg = "Juggernaut: " + msg + " on " + this.options.host + ':' + this.options.port;
this.hasFirebug ? console.log(msg) : alert(msg);
}
- },
-
- fire_event: function(fx_name) {
- $(document).fire("juggernaut:" + fx_name);
- },
-
- initialize: function(options) {
- this.options = options;
- Event.observe(window, 'load', function() {
- juggernaut = this;
- this.appendFlashObject()
- }.bind(this));
- },
-
- initialized: function(){
+ }
+
+Juggernaut.fn.initialized = function(){
this.fire_event('initialized');
this.connect();
- },
+ }
- broadcast: function(body, type, client_ids, channels){
- var msg = new Hash();
- msg.set('command', 'broadcast');
- msg.set('body', body);
- msg.set('type', (type||'to_channels'));
- if(channels) msg.set('channels', channels);
- if(client_ids) msg.set('client_ids', client_ids);
- this.sendData(msg.toJSON());
- },
+Juggernaut.fn.broadcast = function(body, type, client_ids, channels){
+ var msg = {command: 'broadcast', body: body, type: (type||'to_channels')}
+ if(channels) msg['channels'] = channels;
+ if(client_ids) msg['client_ids'] = client_ids;
+ this.sendData(Juggernaut.toJSON(msg));
+ }
- sendData: function(data){
+Juggernaut.fn.sendData = function(data){
this.swf().sendData(escape(data));
- },
+ }
- connect: function(){
+Juggernaut.fn.connect = function(){
if(!this.is_connected){
this.fire_event('connect');
this.swf().connect(this.options.host, this.options.port);
}
- },
+ }
- disconnect: function(){
+Juggernaut.fn.disconnect = function(){
if(this.is_connected) {
this.swf().disconnect();
this.is_connected = false;
}
- },
-
- connected: function(e) {
- var handshake = new Hash();
- handshake.set('command', 'subscribe');
- if(this.options.session_id) handshake.set('session_id', this.options.session_id);
- if(this.options.client_id) handshake.set('client_id', this.options.client_id);
- if(this.options.channels) handshake.set('channels', this.options.channels);
+ }
+
+Juggernaut.fn.handshake = function() {
+ var handshake = {};
+ handshake['command'] = 'subscribe';
+ if(this.options.session_id) handshake['session_id'] = this.options.session_id;
+ if(this.options.client_id) handshake['client_id'] = this.options.client_id;
+ if(this.options.channels) handshake['channels'] = this.options.channels;
if(this.currentMsgId) {
- handshake.set('last_msg_id', this.currentMsgId);
- handshake.set('signature', this.currentSignature);
+ handshake['last_msg_id'] = this.currentMsgId;
+ handshake['signature'] = this.currentSignature;
}
- this.sendData(handshake.toJSON());
+
+ return handshake;
+ }
+
+Juggernaut.fn.connected = function(e) {
+ var json = Juggernaut.toJSON(this.handshake())
+ this.sendData(json);
this.ever_been_connected = true;
this.is_connected = true;
setTimeout(function(){
@@ -100,24 +93,57 @@ var Juggernaut = Class.create({
}.bind(this), 1 * 1000);
this.logger('Connected');
this.fire_event('connected');
- },
+ }
- receiveData: function(e) {
- var msg = unescape(e.toString()).evalJSON();
+// OVERRIDE FOR CHAT STYLE APPS - POSSIBLE MALICIOUS CONTENT CAN BE EVALED
+Juggernaut.fn.receiveData = function(e) {
+ var msg = Juggernaut.parseJSON(unescape(e.toString()));
this.currentMsgId = msg.id;
this.currentSignature = msg.signature;
this.logger("Received data:\n" + msg.body + "\n");
- eval(msg.body);
- },
+ eval(msg.body);
+ }
+
+var juggernaut;
+
+/*** START PROTOTYPE SPECIFIC - OVERRIDE FOR OTHER FRAMEWORKS ***/
+Juggernaut.fn.fire_event = function(fx_name) {
+ $(document).fire("juggernaut:" + fx_name);
+ }
+
+Juggernaut.fn.bindToWindow = function() {
+
+ Event.observe(window, 'load', function() {
+ juggernaut = this;
+ this.appendFlashObject()
+ }.bind(this));
+
+ }
+
+Juggernaut.toJSON = function(hash) {
+ return Object.toJSON(hash);
+ }
+
+Juggernaut.parseJSON = function(string) {
+ return string.evalJSON();
+ }
+
+Juggernaut.fn.swf = function(){
+ return $(this.options.swf_name);
+ }
- appendFlashObject: function(){
+Juggernaut.fn.appendElement = function() {
+ this.element = new Element('div', { id: 'juggernaut' });
+ $(document.body).insert({ bottom: this.element });
+ }
+
+/*** END PROTOTYPE SPECIFIC ***/
+
+Juggernaut.fn.appendFlashObject = function(){
if(this.swf()) {
throw("Juggernaut error. 'swf_name' must be unique per juggernaut instance.");
}
- this.element = new Element('div', {
- id: 'juggernaut'
- });
- $(document.body).insert({ bottom: this.element });
+ Juggernaut.fn.appendElement();
swfobject.embedSWF(
this.options.swf_address,
'juggernaut',
@@ -129,36 +155,33 @@ var Juggernaut = Class.create({
{},
{'id': this.options.swf_name, 'name': this.options.swf_name}
);
- },
-
- swf: function(){
- return $(this.options.swf_name);
- },
+ }
- refreshFlashObject: function(){
+
+Juggernaut.fn.refreshFlashObject = function(){
this.swf().remove();
this.appendFlashObject();
- },
+ }
- errorConnecting: function(e) {
+Juggernaut.fn.errorConnecting = function(e) {
this.is_connected = false;
if(!this.attempting_to_reconnect) {
this.logger('There has been an error connecting');
this.fire_event('errorConnecting');
this.reconnect();
}
- },
+ }
- disconnected: function(e) {
+Juggernaut.fn.disconnected = function(e) {
this.is_connected = false;
if(!this.attempting_to_reconnect) {
this.logger('Connection has been lost');
this.fire_event('disconnected');
this.reconnect();
}
- },
+ }
- reconnect: function(){
+Juggernaut.fn.reconnect = function(){
if(this.options.reconnect_attempts){
this.attempting_to_reconnect = true;
this.fire_event('reconnect');
@@ -179,4 +202,4 @@ the first in ' + (this.options.reconnect_intervals || 3) + ' seconds');
}
}
-});
+
Please sign in to comment.
Something went wrong with that request. Please try again.