Giter Club home page Giter Club logo

juggernaut's Introduction

#Juggernaut

Juggernaut has been deprecated! Read why here.

Juggernaut gives you a realtime connection between your servers and client browsers. You can literally push data to clients using your web application, which lets you do awesome things like multiplayer gaming, chat, group collaboration and more.

Juggernaut is built on top of Node.js and is super simple and easy to get going.

##Features

  • Node.js server
  • Ruby client
  • Supports the following protocols:
    • WebSocket
    • Adobe Flash Socket
    • ActiveX HTMLFile (IE)
    • Server-Sent Events (Opera)
    • XHR with multipart encoding
    • XHR with long-polling
  • Horizontal scaling
  • Reconnection support
  • SSL support

As you can see, Juggernaut supports a variety of protocols. If one isn't supported by a client, Juggernaut will fallback to one that is.

Supported browsers are:

  • Desktop
    • Internet Explorer >= 5.5
    • Safari >= 3
    • Google Chrome >= 4
    • Firefox >= 3
    • Opera 10.61
  • Mobile
    • iPhone Safari
    • iPad Safari
    • Android WebKit
    • WebOs WebKit

##Requirements

  • Node.js
  • Redis
  • Ruby (optional)

##Setup

###Install Node.js

If you're using the Brew package management system, use that:

brew install node

Or follow the Node build instructions

###Install Redis

If you're using the Brew package, use that:

brew install redis

Or follow the Redis build instructions

###Install Juggernaut

Juggernaut is distributed by npm, you'll need to install that first if you haven't already.

npm install -g juggernaut

###Install the Juggernaut client gem

This step is optional, but if you're planning on using Juggernaut with Ruby, you'll need the gem.

gem install juggernaut

##Running

Start Redis:

redis-server

Start Juggernaut:

juggernaut

That's it! Now go to http://localhost:8080 to see Juggernaut in action.

##Basic usage

Everything in Juggernaut is done within the context of a channel. JavaScript clients can subscribe to a channel which your server can publish to. First, we need to include Juggernaut's application.js file. By default, Juggernaut is hosted on port 8080 - so we can just link to the file there.

<script src="http://localhost:8080/application.js" type="text/javascript" charset="utf-8"></script>

We then need to instantiate the Juggernaut object and subscribe to the channel. As you can see, subscribe takes two arguments, the channel name and a callback.

<script type="text/javascript" charset="utf-8">
  var jug = new Juggernaut;
  jug.subscribe("channel1", function(data){
    console.log("Got data: " + data);
  });
</script>

That's it for the client side. Now, to publish to the channel we'll write some Ruby:

require "juggernaut"
Juggernaut.publish("channel1", "Some data")

You should see the data we sent appear instantly in the open browser window. As well as strings, we can even pass objects, like so:

Juggernaut.publish("channel1", {:some => "data"})

The publish method also takes an array of channels, in case you want to send a message to multiple channels co-currently.

Juggernaut.publish(["channel1", "channel2"], ["foo", "bar"])

That's pretty much the gist of it, the two methods - publish and subscribe. Couldn't be easier than that!

##Flash

Adobe Flash is optional, but it's the default fallback for a lot of browsers until WebSockets are supported. However, Flash needs a XML policy file to be served from port 843, which is restricted. You'll need to run Juggernaut with root privileges in order to open that port.

sudo juggernaut

You'll also need to specify the location of WebSocketMain.swf. Either copy this file (from Juggernaut's public directory) to the root public directory of your application, or specify it's location before instantiating Juggernaut:

window.WEB_SOCKET_SWF_LOCATION = "http://juggaddress:8080/WebSocketMain.swf"

As I mentioned above, using Flash with Juggernaut is optional - you don't have to run the server with root privileges. If Flash isn't available, Juggernaut will use WebSockets (the default), Comet or polling.

##SSL

Juggernaut has SSL support! To activate, just put create a folder called 'keys' in the 'juggernaut' directory, containing your privatekey.pem and certificate.pem files.

>> mkdir keys
>> cd keys
>> openssl genrsa -out privatekey.pem 1024 
>> openssl req -new -key privatekey.pem -out certrequest.csr 
>> openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem

Then, pass the secure option when instantiating Juggernaut in JavaScript:

var juggernaut = new Juggernaut({secure: true})

All Juggernaut's communication will now be encrypted by SSL.

##Scaling

The only centralised (i.e. potential bottle neck) part to Juggernaut is Redis. Redis can support hundreds of thousands writes a second, so it's unlikely that will be an issue.

Scaling is just a case of starting up more Juggernaut Node servers, all sharing the same Redis instance. Put a TCP load balancer in front them, distribute clients with a Round Robin approach, and use sticky sessions.

It's worth noting that the latest WebSocket specification breaks support for a lot of HTTP load balancers, so it's safer just using a TCP one.

##Client Events

Juggernaut's JavaScript client has a few events that you can bind to:

  • connect
  • disconnect
  • reconnect

Juggernaut also triggers data events in the context of an channel. You can bind to that event by just passing a callback to the subscribe function. Here's an example of event binding. We're using jQuery UI to show a popup when the client loses their connection to our server.

var jug = new Juggernaut;

var offline = $("<div></div>")
	.html("The connection has been disconnected! <br /> " + 
	      "Please go back online to use this service.")
	.dialog({
		autoOpen: false,
		modal:    true,
		width:    330,
		resizable: false,
		closeOnEscape: false,
		title: "Connection"
	});

jug.on("connect", function(){ 
  offline.dialog("close");
});

jug.on("disconnect", function(){ 
  offline.dialog("open");
});

// Once we call subscribe, Juggernaut tries to connnect.
jug.subscribe("channel1", function(data){
  console.log("Got data: " + data);
});

##Excluding certain clients

It's a common use case to send messages to every client, except one. For example, this is a common chat scenario:

  • User creates chat message
  • User's client appends the message to the chat log, so the user sees it instantly
  • User's client sends an AJAX request to the server, notifying it of the new chat message
  • The server then publishes the chat message to all relevant clients

Now, the issue above is if the server publishes the chat message back to the original client. In which case, it would get duplicated in the chat logs (as it already been created). We can resolve this issue by recording the client's Juggernaut ID, and then passing it as an :except option when Juggernaut publishes.

You can pass the Juggernaut session ID along with any AJAX requests by hooking into beforeSend, which is triggered by jQuery before sending any AJAX requests. The callback is passed an XMLHttpRequest, which we can use to set a custom header specifying the session ID.

var jug = new Juggernaut;

jQuery.beforeSend(function(xhr){
  xhr.setRequestHeader("X-Session-ID", jug.sessionID);
});

Now, when we publish to a channel, we can pass the :except option, with the current client's session ID.

Juggernaut.publish(
  "/chat",
  params[:body],
  :except => request.headers["X-Session-ID"]
)

Now, the original client won't get the duplicated chat message, even if it's subscribed to the /chat channel.

##Server Events

When a client connects & disconnects, Juggernaut triggers a callback. You can listen to these callbacks from the Ruby client,

Juggernaut.subscribe do |event, data|
  # Use event/data
end

The event is either :subscribe or :unsubscribe. The data variable is just a hash of the client details:

{"channel" => "channel1", "session_id" => "1822913980577141", "meta" => "foo"}

##Metadata

You'll notice there's a meta attribute in the server event example above. Juggernaut lets you attach meta data to the client object, which gets passed along to any server events. For example, you could set User ID meta data - then you would know which user was subscribing/unsubscribing to channels. You could use this information to build a live Roster of online users.

var jug = new Juggernaut;
jug.meta = {user_id: 1};

##Using Juggernaut from Python

You don't have to use Ruby to communicate with Juggernaut. In fact, all that is needed is a Redis adapter. Here we're using Python with redis-py.

import redis
import json

msg = {
  "channels": ["channel1"],
  "data": "foo"
}

r = redis.Redis()
r.publish("juggernaut", json.dumps(msg))

##Using Juggernaut from Node.js

Similar to the Python example, we can use a Node.js Redis adapter to publish to Juggernaut.

var redis   = require("redis");

var msg = {
  "channels": ["channel1"],
  "data": "foo"
};

var client = redis.createClient();
client.publish("juggernaut", JSON.stringify(msg));

##Building a Roster

So, let's take all we've learnt about Juggernaut, and apply it to something practical - a live chat roster. Here's the basic class. We're using SuperModel with the Redis adapter. Any changes to the model will be saved to our Redis data store. We're also associating each Roster record with a user.

class Roster < SuperModel::Base
  include SuperModel::Redis::Model
  include SuperModel::Timestamp::Model

  belongs_to :user
  validates_presence_of :user_id

  indexes :user_id
end

Now let's integrate the Roster class with Juggernaut. We're going to listen to Juggernaut's server events - fetching the user_id out of the events meta data, and calling event_subscribe or event_unsubscribe, depending on the event type.

def self.subscribe
  Juggernaut.subscribe do |event, data|
    user_id = data["meta"] && data["meta"]["user_id"]
    next unless user_id
      
    case event
    when :subscribe
      event_subscribe(user_id)
    when :unsubscribe
      event_unsubscribe(user_id)
    end
  end
end

Let's implement those two methods event_subscribe & event_unsubscribe. We need to take into account they may be called multiple times for a particular user_id, if a User opens multiple browser windows co-currently.

def event_subscribe(user_id)
  record = find_by_user_id(user_id) || self.new(:user_id => user_id)
  record.increment!
end

def event_unsubscribe(user_id)
  record = find_by_user_id(user_id)
  record && record.decrement!
end

We need to add a count attribute to the Roster class, so we can track if a client has completely disconnected from the system. Whenever clients subscribes to a channel, increment! will get called and the count attribute will be incremented, conversly whenever they disconnect from that channel decrement! will get called and count decremented.

attributes :count

def count
  read_attribute(:count) || 0
end

def increment!
  self.count += 1
  save!
end

def decrement!
  self.count -= 1
  self.count > 0 ? save! : destroy
end

When decrement! is called, we check to see if the count is zero, i.e. a client is no longer connected, and destroy the record if necessary. Now, at this point we have a live list of Roster records indicating who's online. We just need to call Roster.subscribe, say in a Rails script file, and Juggernaut events will be processed.

#!/usr/bin/env ruby
require File.expand_path('../../config/environment',  __FILE__)

puts "Starting Roster"
Roster.subscribe 

There's no point, however, in having a live Roster unless we can show that to users - which is the subject of the next section, observing models.

##Observing models

We can create an Juggernaut observer, which will observe some of the models, notifying clients when they're changed.

class JuggernautObserver < ActiveModel::Observer
  observe :roster
  
  def after_create(rec)
    publish(:create, rec)
  end

  def after_update(rec)
    publish(:update, rec)
  end

  def after_destroy(rec)
    publish(:destroy, rec)
  end

  protected
    def publish(type, rec)
      channels = Array(rec.observer_clients).map {|c| "/observer/#{c}" }
      Juggernaut.publish(
        channels, 
        {
          :id     => rec.id, 
          :type   => type, 
          :klass  => rec.class.name,
          :record => rec
        }
      )
    end
end

So, you can see we're calling the publish method whenever a record is created/updated/destroyed. You'll notice that we're calling observer_clients on the updated record. This is a method that application specific, and needs to be implemented on the Roster class. It needs to return an array of user_ids associated with the record.

So, as to the JavaScript side to the observer, we need to subscribe to a observer channel and set a callback. Now, whenever a Roster record is created/destroyed, the process function will be called. We can then update the UI accordingly.

var process = function(msg){
  // msg.klass
  // msg.type
  // msg.id
  // msg.record 
};

var jug = new Juggernaut;
jug.subscribe("/observer/" + user_id, process);

##Full examples

You can see the full examples inside Holla, specifically roster.rb, juggernaut_observer.rb and application.juggernaut.js.

juggernaut's People

Contributors

duncanbeevers avatar jskulski avatar kamal avatar maccman avatar raid5 avatar rkelln avatar sespindola avatar vroy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

juggernaut's Issues

As a matter of convenience, I think it would be best if there was an unpacked application.js bundled?

The current [packed] version could continue to be supplied, also, but it would be nice for those of us actively debugging to be able to maintain on tracking trunk while still maintaining debugging ability.

As is, I'm often faced with errors on "line 1" of application.js, at which point I run it through a formatter and then repeat this each time I do another pull.

If this isn't practical for reasons I've not considered, no worries. I appreciate all the work you (and everyone who has contributed!) has put in.

Private server?

Hi

Once my Juggernaut server is online, how can I prevent people from creating their own channels and/or publishing? I can secure my channels by using random tokens as names but I don't see how I can stop someone from using my server for his own ends.

Thanks

Socket.io Error while starting the server

I have already worked with juggernaut(ruby) so just thought of exploring juggernaut on node but it seem that i have to wait for until the error get resolved .I'm new to node so cant figure what the error is

throw e;
^
Error: Cannot find module 'socket.io'
at loadModule (node.js:275:15)
at require (node.js:411:14)
at Object. (/home/virenegi/Desktop/juggernaut/lib/juggernaut/server.js:4:16)
at Module._compile (node.js:462:23)
at Module._loadScriptSync (node.js:469:10)
at Module.loadSync (node.js:338:12)
at loadModule (node.js:283:14)
at require (node.js:411:14)
at Object. (/home/virenegi/Desktop/juggernaut/lib/juggernaut/index.js:4:15)
at Module._compile (node.js:462:23)

My node version is 0.2.4 and i also followed the step mention in http://sixarm.com/about/node_js_socket_io_fix_for_sys_and_util.html and make resulted in no error.

Server crashes on unproperly formatted message

If you send a message with unexpected strcture (e.g. a string) the server will crash. I believe it should be fixed since otherwise it cannot be safely used in production.

Example of error:

SyntaxError: Unexpected token ILLEGAL
at Object.parse (native)
at Function.fromJSON (/home/mrbrdo/rails/mystery_chat/juggernaut/lib/juggernaut/message.js:8:24)
at [object Object].onmessage (/home/mrbrdo/rails/mystery_chat/juggernaut/lib/juggernaut/connection.js:19:27)
at [object Object]. (lib/superclass.js:42:19)
at [object Object].emit (events:26:26)
at [object Object]._onMessage (lib/socket.io/client.js:49:8)
at [object Object]._handle (lib/socket.io/transports/websocket.js:100:8)
at Stream. (lib/socket.io/transports/websocket.js:78:8)
at Stream.emit (events:26:26)
at IOWatcher.callback (net:484:33)

Juggernaut dies after a few days with "EMFILE, Too many open files"

After a couple of days of Juggernaut running (with moderate usage), it will die out with the following error:


net:891
self.fd = socket(self.type);
^
Error: EMFILE, Too many open files
at net:891:19
at Object.lookup (dns:138:5)
at Stream.connect (net:886:9)
at Timer.callback (/usr/local/lib/node/.npm/redis-client/0.3.5/package/lib/redis-client.js:852:29)

at node.js:757:9

As far as I can tell, sessions are properly being disconnected. I'm also only establishing one connection to Juggernaut per page load, so I'm not totally sure what I could optimize to keep this issue from happening. Any help is greatly appreciated!

Allow hostname for server.listen

Since I have mutliple IP addresses on my maschine, i only want one of them for the port. Please allow to specify the full http.listen options (at least port AND host).

Thanks in advance.

missed messages while "connecting"

I have a simple Rails app which subscribes to /channel in the header with javascript. The callback appends the data to a list on the page.

The page also has an AJAX (remote) button which publishes a message to /channel from the controller.

So the button causes the list to grow. Except if it pressed while juggernaut is still initially "connecting". Is there a recommended solution to this problem? Perhaps some kind of callback that I can use to un-disable the button when the connection is established?

Constantly reconnecting after restarting server.js

If you restart the server at some point then the clients begin reconnecting infinitely:

Subscribing to channel1
Connected
Disconnected
Reconnecting
Reconnecting
Connected
Disconnected
Reconnecting
Reconnecting
Connected
Disconnected
Reconnecting
Reconnecting

this is what server side looks like:

root@ubuntu:~/rails/juggernaut# node server.js 
2 Dec 14:24:50 - socket.io ready - accepting connections
2 Dec 14:24:59 - Initializing client with transport "flashsocket"
2 Dec 14:24:59 - Client 1727252840064466 connected
2 Dec 14:24:59 - Received: {"type":"subscribe","channel":"channel1"}
2 Dec 14:24:59 - Client subscribing to: channel1
^Croot@ubuntu:~/rails/juggernaut# node server.js 
2 Dec 14:25:18 - socket.io ready - accepting connections
2 Dec 14:25:18 - Initializing client with transport "xhr-polling"
2 Dec 14:25:18 - Client 11553931422531605 connected
2 Dec 14:25:19 - Received: {"type":"subscribe","channel":"channel1"}
2 Dec 14:25:19 - Client subscribing to: channel1
2 Dec 14:25:30 - Initializing client with transport "xhr-multipart"
2 Dec 14:25:30 - Client 9081839574500918 connected
2 Dec 14:25:31 - Received: {"type":"subscribe","channel":"channel1"}
2 Dec 14:25:31 - Client subscribing to: channel1
2 Dec 14:25:47 - Client 11553931422531605 disconnected
2 Dec 14:25:51 - Client 9081839574500918 disconnected
2 Dec 14:25:51 - Initializing client with transport "xhr-polling"
2 Dec 14:25:51 - Client 29828460165299475 connected
2 Dec 14:25:52 - Received: {"type":"subscribe","channel":"channel1"}
2 Dec 14:25:52 - Client subscribing to: channel1

same story when you start the server after starting the client.
note that th client numbers are different all the time but actually the client is one and the same browser window.

Error when trying to start Juggernaut

Hi,

I installed all pre-reqs as per README, redis works fine. However, when I try to start the server, I get the following error:

node server.js
3 Dec 00:40:14 - socket.io ready - accepting connections

node.js:66
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: EADDRINUSE, Address already in use
at Server._doListen (net.js:953:42)
at net.js:924:14
at Object.lookup (dns.js:126:5)
at Server.listen (net.js:918:20)
at [object Object].listen (/home/mark/ruby/work/juggernaut/juggernaut/lib/juggernaut/server.js:52:21)
at Object.listen (/home/mark/ruby/work/juggernaut/juggernaut/lib/juggernaut/index.js:9:10)
at Object. (/home/mark/ruby/work/juggernaut/juggernaut/server.js:2:12)
at Module._compile (node.js:347:32)
at Object..js (node.js:355:14)
at Module.load (node.js:278:27)

I presume that some ports are already being used on my system and this is why I get that error however, I checked and nothing is already serving port 8080 (which I assume juggernaut is using). I even changed the port in juggernaut.js ( this.port = this.options.port || 8080;), assuming this is where it comes from, to some random port, still get that error (slim chance that a random number is also being listened to). What other ports do I need to worry about?

Cheers.

JS client connect problem

There is a problem in the client code of juggernaut.js (in public dir). In the connect method, this line should be changed:
if (this.state == "connected") return;
to:
if (this.state == "connected" || this.state == "connecting") return;

The current problem is when using flashsocket and subscribing to two channels one after another, socket.connect will be called 2 times and will result in endless loop. Note still this is not thread-safe but for JS it should be ok.

Uncaught exception: ReferenceError: Security violation only in Opera

I continue to receive the error below in opera after installing the latest of socket.io-node and juggernaut. IE 8, FF, Chrome all connect. opera is the only client I have tested so far that is not.

Uncaught exception: ReferenceError: Security violation

Error thrown at line 1, column 24211 in () in http://204.236.224.20:8080/application.js:
this._xhr.send()
called from line 1, column 12221 in () in http://204.236.224.20:8080/application.js:
this._get();
called from line 1, column 23558 in () in http://204.236.224.20:8080/application.js:
io.Transport.XHR.prototype.connect.call(this)
called via Function.prototype.call() from line 1, column 30910 in () in http://204.236.224.20:8080/application.js:
this.transport.connect();
called from line 1, column 84704 in () in http://204.236.224.20:8080/application.js:
this.socket.connect()
called from line 1, column 85128 in (b, c) in http://204.236.224.20:8080/application.js:
this.connect()
called from line 4, column 8 in http://204.236.224.20:3000/chat/enter_room/Yoruba_room:
jug.subscribe("Yoruba_room", function(data){

application.js

Is there a reason the application.js is all on a single line? I made change to the order of transports and the line breaks into several causing javascript errors in browsers.

when i start sudo node server.js i am getting this error

2 Mar 19:05:12 - socket.io ready - accepting connections

node.js:116
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: EADDRINUSE, Address already in use
at Server._doListen (net.js:1062:5)
at net.js:1033:14
at Object.lookup (dns.js:132:33)
at Server.listen (net.js:1027:20)
at [object Object].listen (/home/openweb/Desktop/juggernaut/lib/juggernaut/server.js:55:21)
at Object.listen (/home/openweb/Desktop/juggernaut/lib/juggernaut/index.js:9:10)
at Object. (/home/openweb/Desktop/juggernaut/server.js:2:12)
at Module._compile (module.js:373:26)
at Object..js (module.js:379:10)
at Module.load (module.js:305:31)

I install node-0.4.0
redis-2.0.3
juggernaut

404 Error

I'm using Ubuntu 10.04 on my developer machine and Debian Lenny on server. I have node 0.4.3, npm, redis 2.2.2. And in both places I am encountering this error.

When i do
> git clone https://github.com/maccman/juggernaut.git --recursive
> cd juggernaut
> node server.js

Everything works fine.

But, when I try to run juggernaut with RunIt as daemon
"exec /usr/local/bin/node /opt/juggernaut/derver.js"

juggernaut is running and I get 404 errors
25 Mar 07:36:46 - socket.io ready - accepting connections
> Error serving / - Not Found
> Error serving /favicon.ico - Not Found
> Error serving / - Not Found
> Error serving /favicon.ico - Not Found

application.js is also unreachable
> Error serving /application.js - Not Found

And when I simply install juggernaut with npm, and run
> juggernaut
> Error serving / - Not Found
> Error serving /favicon.ico - Not Found

..I also get this strange 404 errors.

Tried with latest node 0.5 pre -- and the same thing.
Tried changing the PORT env variable -- no effect.

Just an idea: I think this is because the "node-static" dependency, because I read somewhere about 404 errors before.. but I don't know how to fix it.

Juggernaut server does not start after non-graceful stop

I wanted to restart juggernaut server so I pressed Ctrl+Z and server stopped.
But, it did not start after that. It started to show some error.
After restarting machine it worked.

Stopping juggernaut with Ctrl+C works fine.

How does Juggernaut compare to Faye?

I'm going to be looking at Juggernaut for use in my app.

Currently, I'm using Faye and it's great, though I feel the internals are hard to understand and adjust, if one needs to do that. I think that's partly owing to the complexity of the Bayeux protocol (which is related to Comet, of course) of which Faye is an implementation (including a websockets implementation not described in the protocol spec). It's also owing, I think, to jcoglan's having in mind that it's Faye's external API that should be "dirt simple" and his not coding it in a manner that's geared for hackability, per se. And I think it's owing to the fact that jcoglan is a wizard and he wrote the code using just about every trick he knows to make the JS as lean and fast as possible.

Anyway, would you be willing to offer a comparison of your juggernaut with Faye? Did you look to Faye when coding juggernaut? What about the Bayeux spec?

I'll admit that I'm typing up this "issue" before properly digging into your code base, but I am hoping to get your thoughts even if I'm able to answer some of my own questions with a look through your code.

http://faye.jcoglan.com/
http://github.com/jcoglan/faye/
http://svn.cometd.com/trunk/bayeux/bayeux.html

cannot find module 'https'

I am running:
Mac OS X 10.6.6
Node 0.2.4
Redis 2.0.3

I installed according to the instructions in the readme (including --recursive). When I run node server.js I get the following:

node.js:63
    throw e;
    ^
Error: Cannot find module 'https'
    at loadModule (node.js:275:15)
    at require (node.js:411:14)
    at Object. (/usr/local/src/juggernaut/lib/juggernaut/server.js:2:16)
    at Module._compile (node.js:462:23)
    at Module._loadScriptSync (node.js:469:10)
    at Module.loadSync (node.js:338:12)
    at loadModule (node.js:283:14)
    at require (node.js:411:14)
    at Object. (/usr/local/src/juggernaut/lib/juggernaut/index.js:4:15)
    at Module._compile (node.js:462:23)

Here's the output I got when I configured node

Checking for program g++ or c++          : /usr/bin/g++ 
Checking for program cpp                 : /usr/bin/cpp 
Checking for program ar                  : /usr/bin/ar 
Checking for program ranlib              : /usr/bin/ranlib 
Checking for g++                         : ok  
Checking for program gcc or cc           : /usr/bin/gcc 
Checking for gcc                         : ok  
Checking for library dl                  : yes 
Checking for openssl                     : not found 
Checking for function SSL_library_init   : yes 
Checking for header openssl/crypto.h     : yes 
Checking for library rt                  : not found 
--- libeio ---
Checking for library pthread             : yes 
Checking for function pthread_create     : yes 
Checking for function pthread_atfork     : yes 
Checking for futimes(2)                  : yes 
Checking for readahead(2)                : no 
Checking for fdatasync(2)                : yes 
Checking for pread(2) and pwrite(2)      : yes 
Checking for sendfile(2)                 : yes 
Checking for sync_file_range(2)          : no 
--- libev ---
Checking for header sys/inotify.h        : not found 
Checking for header sys/epoll.h          : not found 
Checking for header port.h               : not found 
Checking for header poll.h               : yes 
Checking for function poll               : yes 
Checking for header sys/event.h          : yes 
Checking for header sys/queue.h          : yes 
Checking for function kqueue             : yes 
Checking for header sys/select.h         : yes 
Checking for function select             : yes 
Checking for header sys/eventfd.h        : not found 
Checking for SYS_clock_gettime           : no 
Checking for library rt                  : not found 
Checking for function nanosleep          : yes 
Checking for function ceil               : yes 
Checking for fdatasync(2) with c++       : no 
'configure' finished successfully (1.286s)

Odd but maybe unrelated is that I most certainly do have openssl (ver 1.0.0d) installed.

Sorry in advance if this is a node problem and not a juggernaut problem...

require 'node-static' should be changed to 'node-static-maccman'

I've just done a clean install of node, npm and juggernaut's latest version (2.0.3), and when I run juggernaut I get the following error:

node.js:178
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: Cannot find module 'node-static'
    at Function._resolveFilename (module.js:320:11)
    at Function._load (module.js:266:25)
    at require (module.js:348:19)
    at Object.<anonymous> (/home/paco/local/node_modules/juggernaut/lib/juggernaut/server.js:7:16)
    at Module._compile (module.js:404:26)
    at Object..js (module.js:410:10)
    at Module.load (module.js:336:31)
    at Function._load (module.js:297:12)
    at require (module.js:348:19)
    at Object.<anonymous> (/home/paco/local/node_modules/juggernaut/lib/juggernaut/index.js:4:15)

Changing line 7 in lib/juggernaut/server.js from:

var nstatic  = require 'node-static'

to

var nstatic  = require 'node-static-maccman'

solves the problem.

TypeError: Object

Hello,

I followed the readme to install all the dependencies as you instruct. After I run node server.js i get:

node.js:63
throw e;
^
TypeError: Object

Nothing more. Just before it errors out it seems it connects to the redis server (it gets a connection but then it is immediately closed). I installed node from the git repo, everything else like you specified in the readme. Also tried all versions of redis server (upto 2.0.1).

Juggernaut.write from client can crash server

From my javascript debug console in my browser, I executed the following line and it caused an exception in the server, taking it down:

jug.write('{"channels":["map_clients"], "data":{"clientConnected": {"session_id": "wat", "coords": {"latitude": 50, "longitude": 50}}}}')

The exception thrown was:

/path/to/rails/vendor/plugins/juggernaut/lib/juggernaut/connection.js:37
        throw "Unknown type"
        ^

I'd prefer if clients couldn't call write directly at all, and rather handle all publishes from ruby serverside, or at least ignore all publish requests from the client. Is this possible or would I need to modify the juggernaut code? (Which is fine but I don't want to if I don't have to)

Thanks.

Problem publishing from Ruby

I have just cloned the repo, and built and instelled the gem (in the client directory).

I also have successfully compiled node.js (master branch).

I installed redis-server (Ubuntu package). And installed the gem redis 2.1.1.

However when I try to publish from Ruby (irb) I get this:

require 'rubygems'
require 'juggernaut'
Juggernaut.publish('channel1', 'data')


RuntimeError: -ERR unknown command 'publish'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/connection.rb:86:in `format_error_reply'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/connection.rb:76:in `format_reply'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/connection.rb:71:in `read'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/client.rb:83:in `read'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/client.rb:30:in `call'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/client.rb:63:in `process'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/client.rb:154:in `ensure_connected'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/client.rb:58:in `process'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/client.rb:118:in `logging'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/client.rb:57:in `process'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis/client.rb:29:in `call'
from /var/lib/gems/1.8/gems/redis-2.1.1/lib/redis.rb:576:in `publish'
from /var/lib/gems/1.8/gems/juggernaut-2.0.1/lib/juggernaut.rb:17:in `publish'
from (irb):3

Any ideas?

Best regards,
Manuel.

Error while starting juggernaut

When I try to start Juggernaut I get this error :

1 Apr 20:21:01 - socket.io ready - accepting connections node_redis: no callback to send error: ERR unknown command 'subscribe'

node.js:134 throw e; // process.nextTick error, or 'error' event on first tick ^ Error: ERR unknown command 'subscribe' at RedisReplyParser. (/usr/local/lib/node/.npm/redis/0.5.9/packag e/index.js:84:27) at RedisReplyParser.emit (events.js:64:17) at RedisReplyParser.send_error (/usr/local/lib/node/.npm/redis/0.5.9/package /lib/parser/javascript.js:251:14) at RedisReplyParser.execute (/usr/local/lib/node/.npm/redis/0.5.9/package/li b/parser/javascript.js:110:22) at RedisClient.on_data (/usr/local/lib/node/.npm/redis/0.5.9/package/index.j s:328:27) at Socket. (/usr/local/lib/node/.npm/redis/0.5.9/package/index.js :99:14) at Socket.emit (events.js:64:17) at Socket._onReadable (net.js:672:14) at IOWatcher.onReadable as callback

this.socket undefined in disconnect function

when I first load a page with Juggernaut enabled, I get this error message:

this.socket is undefined

I did some snooping and found it was happening in this line:

b.prototype.disconnect = function() { 
  this.socket.close();
  return this
};

I took out this.socket.close(); and everything runs fine, but this doesn't seem like a great solution ;)

one thing that I noticed is that this is the disconnect function for web sockets, though I am running on flash sockets. The connect() function for flash sockets runs, but the corresponding disconnect() function:

b.prototype.disconnect=function() {
  this._destroy();
  return io.Transport.XHR.prototype.disconnect.call(this)
};

never gets called.

Here are my stats:
Mac OS X 10.6.6
Firefox 3.6.13
Juggernaut, just pulled
Redis 2.2.1
Node 0.4.1

Juggernaut falls back to xhr-multipart in Firefox 3.6 even when Flash available

From a clean clone from master, when I load the demo page (:8080/index.html) in Firefox 3.6.8, it falls back to xhr-multipart after four seconds, even though Flash is available.

I looked in the socket.io code and traced the checking of Transport mechanisms, and it actually tries to use Flashsocket, even downloading the .swf, before timing out for some reason.

I figure it must be a problem in Juggernaut since it would be a more major issue in socket.io.

problem with ruby client redis pub

Hello Mac

Im having issues with the ruby client , when i do Juggernaut.publish(["channel1"] , "foo")
i get an RuntimeError: -ERR unknown command 'publish', but i think that is an redis gem error

what versions of redis and redis-rb do you use ? i working with redis 1.2.6 and i tryied the latests of redis-rb and 1.0.0 version , with similar results

Enabling SSL prevents Juggernaut from serving any files

Hey,

I followed the instructions to enable SSL (created the keys directory, created the key/self-signed certificate), and now Juggernaut stalls when trying to server files. It will open the connection (Serving /application.js - OK), but it will never serve any data to the browser. I tried to wget the application.js URL and it never moved past 0 bytes received.

I've tried with a real SSL certificate too without any luck. I'm running nodejs 0.2.5 on Ubuntu with the latest Juggernaut (running as root) and included libraries. Any help would be greatly appreciated!

client unsubscribe missing

An unsubscribe method is missing on the client-side Juggernaut class (it is already implemented in server).
Note: I am heavily modifying jug to fit my needs so I cannot simply fork and add pull requests, sorry.

Suggestion for implementation:
Juggernaut.fn.unsubscribe = function(channel){
if ( !channel ) throw "Must provide a channel";

  var message     = new Juggernaut.Message;
  message.type    = "unsubscribe";
  message.channel = channel;
  if (this.state == "connected")
    this.write(message);
};

Problem with utils

Hello there,
I am trying to start the node server but I got:
The 'sys' module is now called 'util'. It should have a similar interface.

node.js:50
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Cannot find module 'utils'
at resolveModuleFilename (node.js:265:13)
at loadModule (node.js:231:20)
at require (node.js:291:14)
at Object. (/Users/panosjee/Documents/Work/GitPlay/juggernaut/lib/juggernaut/channel.js:2:13)
at Module._compile (node.js:348:23)
at Object..js (node.js:356:12)
at Module.load (node.js:279:25)
at loadModule (node.js:251:12)
at require (node.js:291:14)
at Object. (/Users/panosjee/Documents/Work/GitPlay/juggernaut/lib/juggernaut/publish.js:4:15)

I tried to require("util") instead of utils but then i got a simple exception:
The 'sys' module is now called 'util'. It should have a similar interface.

node.js:50
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Object

I search for any node-utils package but it seemed it was not what I needed.
I am using node v0.3.1-pre <- oops it seems it is the unstable version, cheching the stable version atm

Send a message to explicit session_id?

Is it possible to send a message (e.g. via Juggernaut object in Ruby) to a specific client instead of a whole channel, when knowing the client's session_id?

Data incorrectly framed by UA. Dropping connection

Hi there, I've enjoyed upgrading to Juggernaut 2 for our simple chat app. It's soo much simpler!

I've been having this problem with Firefox 3 and its flashsocket fallback. I've placed the websocket file in the root of the site. The first time you try to connect you get this in the logs (production).

22 Nov 23:26:37 - Initializing client with transport "flashsocket"
22 Nov 23:26:37 - Client 24364942777901888 connected
22 Nov 23:26:38 - Data incorrectly framed by UA. Dropping connection
22 Nov 23:26:38 - Client 24364942777901888 disconnected
22 Nov 23:26:39 - Initializing client with transport "xhr-polling"
22 Nov 23:26:39 - Client 2361341412179172 connected
22 Nov 23:26:39 - Initializing client with transport "xhr-multipart"
22 Nov 23:26:39 - Client 6185610580723733 connected

If you refresh the page it works fine:

22 Nov 23:54:33 - Initializing client with transport "flashsocket"
22 Nov 23:54:33 - Client 14171182038262486 connected

I think it's a socket.io problem but any help would be greatly appreciated.

Let me know if I should post it over there instead :)

Cheers,

Brendon

Incorrect JS for IE8

In juggernaut.js, in the Juggernaut.fn.trigger function, this line:
var args = [].splice.call(Juggernaut.fn.trigger.arguments, 0);
Does not seem to be working in IE8 correctly (no error but user-defined callbacks never get called). Possible fix (tested in FF, IE8, chrome and opera, seems to work) is to replace it with:
var args = [];
for (var i=0; i<arguments.length; i++)
args.push(arguments[i]);

Problem running node server.js outside of "juggernaut" folder

Thanks for the great work! But I have problems running it in production as a daemon.

Running node server.js in the "juggernaut" folder works great.

.. but when I'm trying to run juggernaut like this "/usr/local/bin/node /opt/juggernaut/server.js "
.. i get:

node.js:63
throw e;
^
Error: ENOENT, No such file or directory './vendor'
at Object.readdirSync (fs:302:18)
at Object.<anonymous> (/opt/juggernaut/index.js:1:77)
at Module._compile (node.js:462:23)
at Module._loadScriptSync (node.js:469:10)
at Module.loadSync (node.js:338:12)
at loadModule (node.js:283:14)
at require (node.js:411:14)
at Object.<anonymous> (/opt/juggernaut/server.js:1:76)
at Module._compile (node.js:462:23)
at Module._loadScriptSync (node.js:469:10)

What am I doing wrong? Or it is a bug?

Simple Chat implmentation

I'm trying to implement the public chat example you describe in the README file.
These are the step I followed. I’m using Rails 3.

  1. I installed Redis 2.0.3 (http://code.google.com/p/redis/)
  2. I installed Node 0.2.4 stable (http://nodejs.org/#download)
  3. I installed juggernaut 2 (git clone git://github.com/maccman/juggernaut.git)
  4. I patched my juggernaut 2 installation. I downloaded the latest version of redis-node-client (http://github.com/maccman/redis-node-client), I took redis-node-client/lib/redis-client.js and I substituted juggernaut/lib/redis-client.js.
  5. If I start redis (./redis-server) and then juggernaut (node server.js) everything works fine. Juggernaut says

 “2 Nov 12:55:38 - socket.io ready - accepting connections”.

Then I created a rails 3 application:

  1. I added a controller called “ChatReceive” with a view “index”
    app/controllers/chat_receive_controller.rb looks like this:

class ChatReceiveController < ApplicationController
  def index
  end
end

app/views/chat_receive/index.html.erb looks like this:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<script src="http://localhost:8080/application.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
  var jug = new Juggernaut;
  jug.subscribe("/chats", function(data){
    var li = $("<li />");
    li.text(data);
    $("#chats").append(li);
  });  
</script>


<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
<title>HTML Strict</title>
</head>
<body>
<h1>Received messages</h1>

<ul id="chats">
</ul>

</body>
</html>

7)I added a controller called “ChatSend” with a view “index”
app/controllers/chat_send_controller.rb looks like this:


class ChatSendController < ApplicationController
  def index
    Juggernaut.publish("/chats", "hello")
  end
end

app/views/chat_send/index.html.erb looks like this:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
</head>
<body>
<h1>Sendig message hello</h1>
</body>
</html>


With Juggernaut and Redis running I open first http://localhost:3000/ChatReceive to receive and display the messages and then I open http://localhost:3000/ChatSend to send a message hello. These are the problem I found:

a) When I open http://localhost:3000/ChatReceive with Firefox 3.6 and Firebug I get this error on the firebug console:


this.socket is undefined
[Break on this error] if(!this.JSON){JSON=function(){functio...]=this[b]}}return(JSON.stringify(a))};

b) When I open http://localhost:3000/ChatReceive I get this error:


   NameError in ChatsendController#index

uninitialized constant ChatSendController::Juggernaut

I get this because my code can’t see the Juggernaut Class. I suppose I should install the juggernaut-plugin for rails (http://github.com/maccman/juggernaut_plugin) but on the README I read that it’s deprecated.

What should I do tho make it work?

Really private channels ?

Hello, I'm trying Juggernaut in order to develop a webgame (with Rails) and I need private channels.

I looked at your example about that but it's seems to not be secure : everybody can open a Javascript console on the website and subscribe to a channel, no ?

So, there is a way to have really private channels ? Using a callback (called on subscribe) to know (by asking to the Rails server, in my case) if the Juggernaut server should accept/refuse the connection ? Does this feature exists ? Would it be hard to implement ?

I have another idea : using encryption with private and public keys (both of these keys have to be injected to the client-side Javascript code to be able to decrypt datas received and crypt data for sending). Can it be reliable ?

Won't connect...

If i go to the 8080 port the "demo" app will connect and works fine, but if I use the same JS code in my app (which is on port 3000, rails app...), it doesn't connect. There is no error in the JS console, and juggernaut log only says:
19 Sep 22:07:37 - Serving /application.js - Not Modified
i use latest git version of juggernaut

"Connection refused" when using RedisToGo

Hi

Juggernaut fails to connect when using RedisToGo (thus assigning process.env.REDISTOGO_URL) because process.env is undefined in events.js.

A first connection is made from publish.js line 8, which works fine, but when redis.createClient is called from events.js line 6 it fails because process.env.REDISTOGO_URL is undefined.

I fixed this by assigning process.env.REDISTOGO_URL in events.js but there is surely a better way to do it (maybe a config.js file?).

Also, we need to add a call to auth(address.auth.replace(/.*:/, '')) in createClient to connect to RedisToGo.

Cheers

Rename REAME to README.mk

Could you rename REAME to README.mk or README.markdown please ?
Github doesn't seem to detect it's an markdown file :)
thanks

Default to flashsocket?

Since websocket has a problem when using HTTP-only proxy, is it possible to force flashsocket?
Or in other case if anyone knows of a way for websocket to bypass the proxy. Since many people use HTTP proxies and obviously juggernaut won't work in Chrome if they do...

index.html example JS error in IE8

The "onload" thing you do in JS in the index.html example does not work in IE8 (JS error). If e.g. using jQuery $() instead it works fine. Sorry that I cannot suggest framework-agnostic alternative, I'm sure it's easy though.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.