jugglite 0.0.1.alpha → 0.0.2.alpha

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - rbx-19mode
data/CHANGELOG ADDED
@@ -0,0 +1,11 @@
1
+ = 0.0.3 / Not Yet Released
2
+
3
+ * TODO: add support for Remy's Polyfill
4
+
5
+ = 0.0.2.alpha / 2012-11-04
6
+
7
+ * standalone binary supports some thin commandline options
8
+
9
+ = 0.0.1.alpha / 2012-11-15
10
+
11
+ * Initial gem release
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in jugglite.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem 'rake'
8
+ end
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Jugglite
2
2
 
3
- Jugglite is a replacement for the incredible [Juggernaut](https://github.com/maccman/juggernaut) by Maccman. It uses [Server Sent Events](http://www.html5rocks.com/en/tutorials/eventsource/basics/) to push events from your application to the client's browser.
3
+ [![Build Status](https://secure.travis-ci.org/andruby/jugglite.png?branch=master)](https://travis-ci.org/andruby/jugglite)
4
+
5
+ Jugglite is a replacement for the incredible [Juggernaut](https://github.com/maccman/juggernaut) by Maccman. It uses [Server Sent Events](http://www.html5rocks.com/en/tutorials/eventsource/basics/) to push events from your application to the client's browser. It uses [Redis](http://www.redis.io) for publish/subscribe and [Thin](http://code.macournoyer.com/thin/) + [EventMachine](https://github.com/eventmachine/eventmachine) to run an evented server that can handle 10K+ concurrent connections.
4
6
 
5
7
  ## Installation
6
8
 
@@ -16,16 +18,72 @@ Or install it yourself as:
16
18
 
17
19
  $ gem install jugglite
18
20
 
19
- ## Usage
21
+ ## Server Usage
22
+
23
+ I use jugglite as rack middleware in development and as a standalone cluster in production behind nginx.
24
+
25
+ ### Stand-alone binary
20
26
 
21
27
  Jugglite comes with a binary. This binary runs a thin server that listens on redis for application messages and passes it along to all connected clients.
22
28
 
23
- You can run the binary from any terminal
24
- `jugglite`
29
+ You can run the binary from any terminal like this (these options are the defaults):
30
+
31
+ `jugglite --address 0.0.0.0 --port 3000 --max-conns 1024`
32
+
33
+ ### As rack middleware
34
+
35
+ Add it to your `config.ru` file:
36
+ `use Juglite::App, path: '/stream'` (use the `path` option )
37
+
38
+ ### As a cluster behind Nginx reverse proxy
39
+
40
+ NOTE: because the html5 SSE implementation requires the connection to have the same hostname and port, you'll need to add a reverse proxy in front of your app and jugglite.
41
+
42
+ TODO with Foreman?
43
+
44
+ ## Client Usage
45
+
46
+ Use the browser's native [Server-Sent Events](http://www.html5rocks.com/en/tutorials/eventsource/basics/) implementation:
47
+
48
+ ```javascript
49
+ es = new EventSource('/stream?channel=yourchannelname');
50
+
51
+ es.addEventListener('message', function(e) {
52
+ // Do something with the data
53
+ console.log(e.data);
54
+ // If you JSON encoded the message
55
+ msg = jQuery.parseJSON(e.data);
56
+ }, false);
57
+
58
+ es.onopen = function(e) {
59
+ // Connection was opened.
60
+ };
61
+
62
+ es.onerror = function(e) {
63
+ if (e.readyState == EventSource.CLOSED) {
64
+ // Connection was closed.
65
+ } else {
66
+ // Some other error?
67
+ };
68
+ };
69
+ ```
70
+
71
+ To support older browsers, use [Remy's](http://html5doctor.com/server-sent-events/) excellent [Pollyfill](https://github.com/remy/polyfills/blob/master/EventSource.js). It does revert to ajax long polling for browsers without a native EventSource implementation. Supports almost every old browser (even IE7).
72
+
73
+ ## Sending messages
74
+
75
+ Use your favorite Redis client to simply publish messages to the channel your clients are subscribing to:
76
+
77
+ ```ruby
78
+ redis = Redis.new
79
+ redis.publish('yourchannelname', 'This is a message')
80
+ # You may want to JSON encode your data
81
+ redis.publish('yourchannelname', {hello: 'world', number: 47}.to_json)
82
+ ```
25
83
 
26
- TODO: Foreman & multiple processes
84
+ ## Performance
27
85
 
28
- TODO: Behind nginx so the client connects on one port
86
+ It's been tested on a local machine with the `spec/benchmark/max_connections.rb` spec up to 16K concurrent connections.
29
87
 
30
88
  ## Contributing
31
89
 
data/bin/jugglite CHANGED
@@ -1,15 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- host = ENV['HOST'] || '127.0.0.1'
4
- port = (ENV['PORT'] || 3000).to_i
5
- file_descriptors = (ENV['FD_SIZE'] || 202400).to_i
6
-
7
2
  require 'jugglite'
8
3
 
9
- new_size = EM.set_descriptor_table_size( file_descriptors )
10
- STDERR.puts "New descriptor-table size is #{new_size}"
11
- EM.epoll
12
- EM.kqueue
4
+ # You may use (almost) all options you would pass to thin
5
+ # eg: --max-conns NUM (might require a higher system "ulimit -n" setting)
6
+ # --port PORT
7
+ # --address HOST
8
+ options = Thin::Runner.new(ARGV).options
9
+ thin = Thin::Server.new(Jugglite::App.new, options[:port], options[:address], options)
10
+
11
+ # Need to increase the descriptor-table for EventMachine
12
+ if options[:max_conns]
13
+ new_size = EM.set_descriptor_table_size( options[:max_conns].to_i )
14
+ STDERR.puts "New descriptor-table size is #{new_size}"
15
+ EM.epoll
16
+ EM.kqueue
17
+ thin.maximum_connections = options[:max_conns] # Need to do this manually because it gets overriden on thin/server.rb:123
18
+ end
13
19
 
14
- STDERR.puts "Starting server at #{host}:#{port}"
15
- Thin::Server.start(host, port, Jugglite::App.new)
20
+ thin.start!
data/lib/jugglite/app.rb CHANGED
@@ -16,7 +16,6 @@ module Jugglite
16
16
  path: '/stream',
17
17
  keepalive_timeout: 20
18
18
  }.merge(options)
19
- STDERR.puts "Registered Jugglite to listen to #{@options[:path]}"
20
19
  @subscription_map = {}
21
20
  EventMachine::next_tick { setup_redis }
22
21
  EventMachine::next_tick { setup_keepalive }
@@ -26,6 +25,7 @@ module Jugglite
26
25
  if @app.nil? || (env["PATH_INFO"] == @options[:path])
27
26
  handle_stream(env)
28
27
  else
28
+ # Running as middleware and path did not match so pass it along
29
29
  @app.call(env)
30
30
  end
31
31
  end
@@ -10,7 +10,7 @@ module Jugglite
10
10
  @queue.push(body)
11
11
  end
12
12
 
13
- def each &blk
13
+ def each(&blk)
14
14
  @body_callback = blk
15
15
  processor = proc { |item|
16
16
  @body_callback.call(item)
@@ -1,3 +1,3 @@
1
1
  module Jugglite
2
- VERSION = "0.0.1.alpha"
2
+ VERSION = "0.0.2.alpha"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jugglite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.alpha
4
+ version: 0.0.2.alpha
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-15 00:00:00.000000000 Z
12
+ date: 2012-12-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thin
@@ -85,6 +85,8 @@ extra_rdoc_files: []
85
85
  files:
86
86
  - .gitignore
87
87
  - .rspec
88
+ - .travis.yml
89
+ - CHANGELOG
88
90
  - Gemfile
89
91
  - LICENSE.txt
90
92
  - README.md