meerkat 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- meerkat (0.2.1)
4
+ meerkat (0.3.0)
5
5
  em-hiredis
6
6
  eventmachine
7
7
  pg
@@ -1,38 +1,72 @@
1
1
  require 'pg'
2
+ require 'date'
2
3
 
3
4
  module Meerkat
4
5
  module Backend
5
6
  class PG
7
+ TABLENAME = 'meerkat_pubsub'.freeze
8
+
6
9
  def initialize(pg_uri = nil)
7
- @pg_uri = pg_uri
10
+ @subs = {}
8
11
  @pg = PGconn.connect pg_uri
12
+ @pg.exec 'SET client_min_messages = warning'
13
+ @pg.exec "CREATE TABLE IF NOT EXISTS #{TABLENAME} (topic varchar(1024), json text, timestamp timestamp default now())"
14
+
15
+ @last_check = @pg.exec('SELECT now() as now').first['now']
16
+
17
+ @sub_client = PGconn.connect pg_uri
18
+ @sub_client.exec "LISTEN #{TABLENAME}"
19
+ EM.next_tick {
20
+ EM.watch(@sub_client.socket, SubscribeClient, @sub_client, lambda {on_notify}) { |c| c.notify_readable = true }
21
+ }
22
+ end
23
+
24
+ def on_notify
25
+ @pg.async_exec "SELECT topic, json, timestamp FROM #{TABLENAME} WHERE timestamp > $1 ORDER BY timestamp ASC", [@last_check] do |rows|
26
+ rows.each do |row|
27
+ @last_check = row['timestamp']
28
+ @subs.each do |topic, callbacks|
29
+ if topic == row['topic']
30
+ callbacks.each { |cb| cb.call row['json'] }
31
+ end
32
+ end
33
+ end
34
+ end
9
35
  end
10
36
 
11
37
  def publish(route, json)
12
- @pg.exec "SELECT pg_notify($1, $2)", [route, json]
38
+ @pg.transaction do |conn|
39
+ conn.exec "DELETE FROM #{TABLENAME} WHERE timestamp < now() - interval '5 seconds'"
40
+ conn.exec "INSERT INTO #{TABLENAME} (topic, json) VALUES ($1, $2)", [route, json]
41
+ conn.exec "NOTIFY #{TABLENAME}"
42
+ end
13
43
  end
14
44
 
15
45
  def subscribe(route, &callback)
16
- pg = PGconn.connect @pg_uri
17
- pg.exec "LISTEN #{PGconn.quote_ident route}"
18
- EM.watch(pg.socket, SubscribeClient, pg, callback) { |c| c.notify_readable = true }
46
+ if @subs[route]
47
+ @subs[route] << callback
48
+ else
49
+ @subs[route] = [callback]
50
+ end
51
+ [route, callback]
19
52
  end
20
53
 
21
- def unsubscribe(pg)
22
- pg.detach
54
+ def unsubscribe(sid)
55
+ @subs[sid[0]].delete sid[1]
23
56
  end
24
57
 
25
58
  module SubscribeClient
26
59
  def initialize(pg, cb)
27
60
  @pg = pg
28
61
  @cb = cb
62
+ @last_check = Time.now
29
63
  end
64
+
30
65
  def notify_readable
31
66
  @pg.consume_input
32
- msg = @pg.notifies
33
- @cb.call(msg[:extra]) if msg
67
+ @cb.call if @pg.notifies
34
68
  end
35
-
69
+
36
70
  def unbind
37
71
  @pg.close
38
72
  end
@@ -1,3 +1,3 @@
1
1
  module Meerkat
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -15,6 +15,19 @@ describe 'Postgres backend' do
15
15
  wait!
16
16
  end
17
17
 
18
+ it 'can publish and subscribe multiple messages' do
19
+ b = Meerkat::Backend::PG.new :dbname => 'postgres'
20
+ i = 5
21
+ j = 0
22
+ b.subscribe '/' do |msg|
23
+ j += 1
24
+ assert_equal 'messsage', msg
25
+ done! if j == i
26
+ end
27
+ i.times { b.publish '/', 'messsage' }
28
+ wait!
29
+ end
30
+
18
31
  it 'can unsubscribe' do
19
32
  b = Meerkat::Backend::PG.new :dbname => 'postgres'
20
33
  sid = b.subscribe 'route' do |msg|
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.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2011-10-25 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
16
- requirement: &70351112360820 !ruby/object:Gem::Requirement
16
+ requirement: &70227841623860 !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: *70351112360820
24
+ version_requirements: *70227841623860
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rack-test
27
- requirement: &70351112360220 !ruby/object:Gem::Requirement
27
+ requirement: &70227841623420 !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: *70351112360220
35
+ version_requirements: *70227841623420
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: thin_async
38
- requirement: &70351112358160 !ruby/object:Gem::Requirement
38
+ requirement: &70227841622800 !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: *70351112358160
46
+ version_requirements: *70227841622800
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: thin-async-test
49
- requirement: &70351112357740 !ruby/object:Gem::Requirement
49
+ requirement: &70227841622140 !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: *70351112357740
57
+ version_requirements: *70227841622140
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: em-minitest-spec
60
- requirement: &70351112357320 !ruby/object:Gem::Requirement
60
+ requirement: &70227841621520 !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: *70351112357320
68
+ version_requirements: *70227841621520
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: yajl-ruby
71
- requirement: &70351112356720 !ruby/object:Gem::Requirement
71
+ requirement: &70227841620900 !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: *70351112356720
79
+ version_requirements: *70227841620900
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: eventmachine
82
- requirement: &70351112356100 !ruby/object:Gem::Requirement
82
+ requirement: &70227841620300 !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: *70351112356100
90
+ version_requirements: *70227841620300
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: em-hiredis
93
- requirement: &70351112355500 !ruby/object:Gem::Requirement
93
+ requirement: &70227841619680 !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: *70351112355500
101
+ version_requirements: *70227841619680
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: pg
104
- requirement: &70351112354800 !ruby/object:Gem::Requirement
104
+ requirement: &70227841619260 !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: *70351112354800
112
+ version_requirements: *70227841619260
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: -2377445987046880713
154
+ hash: 914174044667917372
155
155
  required_rubygems_version: !ruby/object:Gem::Requirement
156
156
  none: false
157
157
  requirements:
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
160
  version: '0'
161
161
  segments:
162
162
  - 0
163
- hash: -2377445987046880713
163
+ hash: 914174044667917372
164
164
  requirements: []
165
165
  rubyforge_project: meerkat
166
166
  rubygems_version: 1.8.6