meerkat 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +27 -2
- data/lib/meerkat.rb +3 -4
- data/lib/meerkat/rackadapter.rb +24 -0
- data/lib/meerkat/version.rb +1 -1
- data/spec/meerkat_spec.rb +35 -1
- metadata +23 -23
data/README.md
CHANGED
@@ -5,6 +5,13 @@ Rack middleware for [Server-Sent Events (HTML5 SSE)](http://www.html5rocks.com/e
|
|
5
5
|
|
6
6
|
Requires an [EventMachine](https://github.com/eventmachine/eventmachine#readme) backed server, like [Thin](http://code.macournoyer.com/thin/) or [Rainbows](http://rainbows.rubyforge.org/) (with the EventMachine backend only).
|
7
7
|
|
8
|
+
Features:
|
9
|
+
* Subscribe for single events
|
10
|
+
* Subscribe for multiple events with patterns
|
11
|
+
* Low memory and CPU usage
|
12
|
+
* Works with all proxies (unlike WebSockets)
|
13
|
+
* Allows publishing from server side as well as from the client side (with POST request)
|
14
|
+
|
8
15
|
Supported backends:
|
9
16
|
|
10
17
|
* In memory, using [EventMachine Channels](http://eventmachine.rubyforge.org/EventMachine/Channel.html), good for single server usage.
|
@@ -42,14 +49,24 @@ On the client:
|
|
42
49
|
```javascript
|
43
50
|
var source = new EventSource('/stream/mychannel');
|
44
51
|
var streamList = document.getElementById('stream');
|
45
|
-
|
52
|
+
// Use #onmessage if you only listen to one topic
|
53
|
+
source.onmessage = function(e) {
|
46
54
|
var li = document.createElement('li');
|
47
55
|
li.innerHTML = JSON.parse(e.data);
|
48
56
|
streamList.appendChild(li);
|
57
|
+
}
|
58
|
+
var multiSource = new EventSource('/my/event/*');
|
59
|
+
// You have to add custom event listerns when you
|
60
|
+
// listen on multiple topics
|
61
|
+
multiSource.addEventListener('/my/event/foo', function(e) {
|
62
|
+
// Do something
|
63
|
+
}, false);
|
64
|
+
multiSource.addEventListener('/my/event/bar', function(e) {
|
65
|
+
// Do something
|
49
66
|
}, false);
|
50
67
|
```
|
51
68
|
|
52
|
-
To push things:
|
69
|
+
To push things from the client:
|
53
70
|
|
54
71
|
```ruby
|
55
72
|
Meerkat.publish "/mychannel", {:any => hash}
|
@@ -59,6 +76,14 @@ Meerkat.publish "/mychannel/3", any_object
|
|
59
76
|
|
60
77
|
The published objects will be JSON serialized (with [Yajl](https://github.com/brianmario/yajl-ruby)) before sent to the backend. Deserialize it in the client.
|
61
78
|
|
79
|
+
From the client:
|
80
|
+
|
81
|
+
```javascript
|
82
|
+
$.post('/stream/mychannel/2', { json: JSON.stringify(my_object) })
|
83
|
+
```
|
84
|
+
|
85
|
+
A simple POST request, with a parameter called 'json' containing a JSON string.
|
86
|
+
|
62
87
|
Read more about Server-Sent Events and the EventSource API on [HTML5Rocks](http://www.html5rocks.com/en/tutorials/eventsource/basics/).
|
63
88
|
|
64
89
|
Examples
|
data/lib/meerkat.rb
CHANGED
@@ -3,7 +3,6 @@ require_relative 'meerkat/rackadapter'
|
|
3
3
|
require_relative 'meerkat/backend/inmemory'
|
4
4
|
require_relative 'meerkat/backend/redis'
|
5
5
|
require_relative 'meerkat/backend/pg'
|
6
|
-
|
7
6
|
require 'yajl'
|
8
7
|
|
9
8
|
module Meerkat
|
@@ -13,9 +12,9 @@ module Meerkat
|
|
13
12
|
@backend = backend
|
14
13
|
end
|
15
14
|
|
16
|
-
def publish(route, message)
|
17
|
-
json = Yajl::Encoder.encode
|
18
|
-
@backend.publish(route, json)
|
15
|
+
def publish(route, message, is_json = false)
|
16
|
+
json = is_json ? message : Yajl::Encoder.encode(message)
|
17
|
+
@backend.publish(route, json)
|
19
18
|
end
|
20
19
|
|
21
20
|
def subscribe(route, &callback)
|
data/lib/meerkat/rackadapter.rb
CHANGED
@@ -12,6 +12,30 @@ module Meerkat
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def call(env)
|
15
|
+
case env['REQUEST_METHOD']
|
16
|
+
when 'GET'
|
17
|
+
listen(env)
|
18
|
+
when 'POST'
|
19
|
+
post(env)
|
20
|
+
else
|
21
|
+
[404, {}, []]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def post(env)
|
26
|
+
req = Rack::Request.new env
|
27
|
+
data = req.params['data'] || req.params['msg'] || req.params['json']
|
28
|
+
if data
|
29
|
+
Meerkat.publish(req.path_info, data, true)
|
30
|
+
[204, {}, []]
|
31
|
+
else
|
32
|
+
[400,
|
33
|
+
{'Content-Type' => 'text/plain'},
|
34
|
+
['Required POST parameter "data", "msg" or "json" is missing']]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def listen(env)
|
15
39
|
body = DeferrableBody.new
|
16
40
|
|
17
41
|
headers = {
|
data/lib/meerkat/version.rb
CHANGED
data/spec/meerkat_spec.rb
CHANGED
@@ -7,8 +7,11 @@ require './lib/meerkat'
|
|
7
7
|
describe 'Meerkat' do
|
8
8
|
include Rack::Test::Methods
|
9
9
|
|
10
|
-
|
10
|
+
before do
|
11
11
|
Meerkat.backend = Meerkat::Backend::InMemory.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def app
|
12
15
|
Rack::Builder.new {
|
13
16
|
meerkat = Meerkat::RackAdapter.new do |m|
|
14
17
|
m.keep_alive = 0.1
|
@@ -33,4 +36,35 @@ describe 'Meerkat' do
|
|
33
36
|
get '/'
|
34
37
|
assert_equal ":", last_response.body.split("\n")[1]
|
35
38
|
end
|
39
|
+
|
40
|
+
it 'should publish POST data and treat it like JSON' do
|
41
|
+
mock = MiniTest::Mock.new
|
42
|
+
mock.expect(:publish, nil, ['/foo', '"bar"'])
|
43
|
+
Meerkat.backend = mock
|
44
|
+
post '/foo', :json => '"bar"'
|
45
|
+
|
46
|
+
assert_equal 204, last_response.status
|
47
|
+
assert mock.verify
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should return error 400 when there is no "json" POST parameters' do
|
51
|
+
post '/', :foo => 'bar'
|
52
|
+
assert_equal 400, last_response.status
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should return error 400 when there is no POST data' do
|
56
|
+
post '/foo'
|
57
|
+
assert_equal 400, last_response.status
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return 404 for anything but GET and POST requests' do
|
61
|
+
delete '/foo'
|
62
|
+
assert_equal 404, last_response.status
|
63
|
+
options '/foo'
|
64
|
+
assert_equal 404, last_response.status
|
65
|
+
head '/foo'
|
66
|
+
assert_equal 404, last_response.status
|
67
|
+
put '/foo'
|
68
|
+
assert_equal 404, last_response.status
|
69
|
+
end
|
36
70
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: meerkat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10
|
12
|
+
date: 2011-11-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
16
|
-
requirement: &
|
16
|
+
requirement: &70262532917760 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70262532917760
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rack-test
|
27
|
-
requirement: &
|
27
|
+
requirement: &70262532917300 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70262532917300
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: thin_async
|
38
|
-
requirement: &
|
38
|
+
requirement: &70262532916880 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70262532916880
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: thin-async-test
|
49
|
-
requirement: &
|
49
|
+
requirement: &70262532916440 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70262532916440
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: em-minitest-spec
|
60
|
-
requirement: &
|
60
|
+
requirement: &70262532916020 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70262532916020
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: yajl-ruby
|
71
|
-
requirement: &
|
71
|
+
requirement: &70262532931940 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70262532931940
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: eventmachine
|
82
|
-
requirement: &
|
82
|
+
requirement: &70262532931520 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70262532931520
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: em-hiredis
|
93
|
-
requirement: &
|
93
|
+
requirement: &70262532931080 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :runtime
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70262532931080
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: pg
|
104
|
-
requirement: &
|
104
|
+
requirement: &70262532930580 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :runtime
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70262532930580
|
113
113
|
description: Requires an evented Ruby dispatcher, like Thin
|
114
114
|
email:
|
115
115
|
- carl.hoerberg@gmail.com
|
@@ -151,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
151
151
|
version: '0'
|
152
152
|
segments:
|
153
153
|
- 0
|
154
|
-
hash:
|
154
|
+
hash: -803937692324384329
|
155
155
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
156
|
none: false
|
157
157
|
requirements:
|
@@ -160,10 +160,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
160
|
version: '0'
|
161
161
|
segments:
|
162
162
|
- 0
|
163
|
-
hash:
|
163
|
+
hash: -803937692324384329
|
164
164
|
requirements: []
|
165
165
|
rubyforge_project: meerkat
|
166
|
-
rubygems_version: 1.8.
|
166
|
+
rubygems_version: 1.8.10
|
167
167
|
signing_key:
|
168
168
|
specification_version: 3
|
169
169
|
summary: Rack middleware for HTML5 Server-Sent Events, with swappable backends
|