faye-redis 0.1.0 → 0.1.1
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/CHANGELOG.txt +9 -0
- data/README.rdoc +3 -2
- data/lib/faye/redis.rb +79 -70
- metadata +36 -17
- data/spec/faye_redis_spec.rb +0 -26
- data/spec/redis.conf +0 -42
- data/spec/spec_helper.rb +0 -3
data/CHANGELOG.txt
ADDED
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Faye::Redis {<img src="https://secure.travis-ci.org/faye/faye-redis-ruby.png
|
1
|
+
= Faye::Redis {<img src="https://secure.travis-ci.org/faye/faye-redis-ruby.png" alt="Build Status" />}[http://travis-ci.org/faye/faye-redis-ruby]
|
2
2
|
|
3
3
|
This plugin provides a Redis-based backend for the {Faye}[http://faye.jcoglan.com]
|
4
4
|
messaging server. It allows a single Faye service to be distributed across many
|
@@ -12,7 +12,7 @@ Pass in the engine and any settings you need when setting up your Faye server.
|
|
12
12
|
|
13
13
|
require 'faye'
|
14
14
|
require 'faye/redis'
|
15
|
-
|
15
|
+
|
16
16
|
bayeux = Faye::RackAdapter.new(
|
17
17
|
:mount => '/',
|
18
18
|
:timeout => 25,
|
@@ -25,6 +25,7 @@ Pass in the engine and any settings you need when setting up your Faye server.
|
|
25
25
|
|
26
26
|
The full list of settings is as follows.
|
27
27
|
|
28
|
+
* <b><tt>:uri</tt></b> - redis URL (example: redis://:secretpassword@example.com:9000/4)
|
28
29
|
* <b><tt>:host</tt></b> - hostname of your Redis instance
|
29
30
|
* <b><tt>:port</tt></b> - port number, default is +6379+
|
30
31
|
* <b><tt>:password</tt></b> - password, if +requirepass+ is set
|
data/lib/faye/redis.rb
CHANGED
@@ -3,60 +3,57 @@ require 'yajl'
|
|
3
3
|
|
4
4
|
module Faye
|
5
5
|
class Redis
|
6
|
-
|
6
|
+
|
7
7
|
DEFAULT_HOST = 'localhost'
|
8
8
|
DEFAULT_PORT = 6379
|
9
9
|
DEFAULT_DATABASE = 0
|
10
10
|
DEFAULT_GC = 60
|
11
11
|
LOCK_TIMEOUT = 120
|
12
|
-
|
12
|
+
|
13
13
|
def self.create(server, options)
|
14
14
|
new(server, options)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def initialize(server, options)
|
18
18
|
@server = server
|
19
19
|
@options = options
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def init
|
23
23
|
return if @redis
|
24
|
-
|
24
|
+
|
25
|
+
uri = @options[:uri] || nil
|
25
26
|
host = @options[:host] || DEFAULT_HOST
|
26
27
|
port = @options[:port] || DEFAULT_PORT
|
27
28
|
db = @options[:database] || DEFAULT_DATABASE
|
28
|
-
auth = @options[:password]
|
29
|
+
auth = @options[:password] || nil
|
29
30
|
gc = @options[:gc] || DEFAULT_GC
|
30
31
|
@ns = @options[:namespace] || ''
|
31
|
-
socket = @options[:socket]
|
32
|
-
|
33
|
-
if
|
34
|
-
@redis
|
35
|
-
|
32
|
+
socket = @options[:socket] || nil
|
33
|
+
|
34
|
+
if uri
|
35
|
+
@redis = EventMachine::Hiredis.connect(uri)
|
36
|
+
elsif socket
|
37
|
+
@redis = EventMachine::Hiredis::Client.new(socket, nil, auth, db).connect
|
36
38
|
else
|
37
|
-
@redis
|
38
|
-
@subscriber = EventMachine::Hiredis::Client.connect(host, port)
|
39
|
-
end
|
40
|
-
if auth
|
41
|
-
@redis.auth(auth)
|
42
|
-
@subscriber.auth(auth)
|
39
|
+
@redis = EventMachine::Hiredis::Client.new(host, port, auth, db).connect
|
43
40
|
end
|
44
|
-
@redis.
|
45
|
-
|
46
|
-
|
41
|
+
@subscriber = @redis.pubsub
|
42
|
+
|
47
43
|
@subscriber.subscribe(@ns + '/notifications')
|
48
44
|
@subscriber.on(:message) do |topic, message|
|
49
45
|
empty_queue(message) if topic == @ns + '/notifications'
|
50
46
|
end
|
51
|
-
|
47
|
+
|
52
48
|
@gc = EventMachine.add_periodic_timer(gc, &method(:gc))
|
53
49
|
end
|
54
|
-
|
50
|
+
|
55
51
|
def disconnect
|
52
|
+
return unless @redis
|
56
53
|
@subscriber.unsubscribe(@ns + '/notifications')
|
57
54
|
EventMachine.cancel_timer(@gc)
|
58
55
|
end
|
59
|
-
|
56
|
+
|
60
57
|
def create_client(&callback)
|
61
58
|
init
|
62
59
|
client_id = @server.generate_id
|
@@ -68,48 +65,53 @@ module Faye
|
|
68
65
|
callback.call(client_id)
|
69
66
|
end
|
70
67
|
end
|
71
|
-
|
68
|
+
|
69
|
+
def client_exists(client_id, &callback)
|
70
|
+
init
|
71
|
+
cutoff = get_current_time - (1000 * 1.6 * @server.timeout)
|
72
|
+
|
73
|
+
@redis.zscore(@ns + '/clients', client_id) do |score|
|
74
|
+
callback.call(score.to_i > cutoff)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
72
78
|
def destroy_client(client_id, &callback)
|
73
79
|
init
|
74
|
-
@redis.
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
after_destroy(client_id, &callback) if i == n
|
80
|
+
@redis.zadd(@ns + '/clients', 0, client_id) do
|
81
|
+
@redis.smembers(@ns + "/clients/#{client_id}/channels") do |channels|
|
82
|
+
i, n = 0, channels.size
|
83
|
+
next after_subscriptions_removed(client_id, &callback) if i == n
|
84
|
+
|
85
|
+
channels.each do |channel|
|
86
|
+
unsubscribe(client_id, channel) do
|
87
|
+
i += 1
|
88
|
+
after_subscriptions_removed(client_id, &callback) if i == n
|
89
|
+
end
|
85
90
|
end
|
86
91
|
end
|
87
92
|
end
|
88
93
|
end
|
89
|
-
|
90
|
-
def
|
91
|
-
@
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
init
|
98
|
-
@redis.zscore(@ns + '/clients', client_id) do |score|
|
99
|
-
callback.call(score != nil)
|
94
|
+
|
95
|
+
def after_subscriptions_removed(client_id, &callback)
|
96
|
+
@redis.del(@ns + "/clients/#{client_id}/messages") do
|
97
|
+
@redis.zrem(@ns + '/clients', client_id) do
|
98
|
+
@server.debug 'Destroyed client ?', client_id
|
99
|
+
@server.trigger(:disconnect, client_id)
|
100
|
+
callback.call if callback
|
101
|
+
end
|
100
102
|
end
|
101
103
|
end
|
102
|
-
|
104
|
+
|
103
105
|
def ping(client_id)
|
104
106
|
init
|
105
107
|
timeout = @server.timeout
|
106
108
|
return unless Numeric === timeout
|
107
|
-
|
109
|
+
|
108
110
|
time = get_current_time
|
109
111
|
@server.debug 'Ping ?, ?', client_id, time
|
110
112
|
@redis.zadd(@ns + '/clients', time, client_id)
|
111
113
|
end
|
112
|
-
|
114
|
+
|
113
115
|
def subscribe(client_id, channel, &callback)
|
114
116
|
init
|
115
117
|
@redis.sadd(@ns + "/clients/#{client_id}/channels", channel) do |added|
|
@@ -120,7 +122,7 @@ module Faye
|
|
120
122
|
callback.call if callback
|
121
123
|
end
|
122
124
|
end
|
123
|
-
|
125
|
+
|
124
126
|
def unsubscribe(client_id, channel, &callback)
|
125
127
|
init
|
126
128
|
@redis.srem(@ns + "/clients/#{client_id}/channels", channel) do |removed|
|
@@ -131,57 +133,64 @@ module Faye
|
|
131
133
|
callback.call if callback
|
132
134
|
end
|
133
135
|
end
|
134
|
-
|
136
|
+
|
135
137
|
def publish(message, channels)
|
136
138
|
init
|
137
139
|
@server.debug 'Publishing message ?', message
|
138
|
-
|
140
|
+
|
139
141
|
json_message = Yajl::Encoder.encode(message)
|
140
142
|
channels = Channel.expand(message['channel'])
|
141
143
|
keys = channels.map { |c| @ns + "/channels#{c}" }
|
142
|
-
|
144
|
+
|
143
145
|
@redis.sunion(*keys) do |clients|
|
144
146
|
clients.each do |client_id|
|
147
|
+
queue = @ns + "/clients/#{client_id}/messages"
|
148
|
+
|
145
149
|
@server.debug 'Queueing for client ?: ?', client_id, message
|
146
|
-
@redis.rpush(
|
150
|
+
@redis.rpush(queue, json_message)
|
147
151
|
@redis.publish(@ns + '/notifications', client_id)
|
152
|
+
|
153
|
+
client_exists(client_id) do |exists|
|
154
|
+
@redis.del(queue) unless exists
|
155
|
+
end
|
148
156
|
end
|
149
157
|
end
|
150
|
-
|
158
|
+
|
151
159
|
@server.trigger(:publish, message['clientId'], message['channel'], message['data'])
|
152
160
|
end
|
153
|
-
|
161
|
+
|
154
162
|
def empty_queue(client_id)
|
155
163
|
return unless @server.has_connection?(client_id)
|
156
164
|
init
|
157
|
-
|
165
|
+
|
158
166
|
key = @ns + "/clients/#{client_id}/messages"
|
159
|
-
|
167
|
+
|
160
168
|
@redis.multi
|
161
169
|
@redis.lrange(key, 0, -1)
|
162
170
|
@redis.del(key)
|
163
171
|
@redis.exec.callback do |json_messages, deleted|
|
172
|
+
next unless json_messages
|
164
173
|
messages = json_messages.map { |json| Yajl::Parser.parse(json) }
|
165
174
|
@server.deliver(client_id, messages)
|
166
175
|
end
|
167
176
|
end
|
168
|
-
|
177
|
+
|
169
178
|
private
|
170
|
-
|
179
|
+
|
171
180
|
def get_current_time
|
172
181
|
(Time.now.to_f * 1000).to_i
|
173
182
|
end
|
174
|
-
|
183
|
+
|
175
184
|
def gc
|
176
185
|
timeout = @server.timeout
|
177
186
|
return unless Numeric === timeout
|
178
|
-
|
187
|
+
|
179
188
|
with_lock 'gc' do |release_lock|
|
180
189
|
cutoff = get_current_time - 1000 * 2 * timeout
|
181
190
|
@redis.zrangebyscore(@ns + '/clients', 0, cutoff) do |clients|
|
182
191
|
i, n = 0, clients.size
|
183
192
|
next release_lock.call if i == n
|
184
|
-
|
193
|
+
|
185
194
|
clients.each do |client_id|
|
186
195
|
destroy_client(client_id) do
|
187
196
|
i += 1
|
@@ -191,32 +200,32 @@ module Faye
|
|
191
200
|
end
|
192
201
|
end
|
193
202
|
end
|
194
|
-
|
203
|
+
|
195
204
|
def with_lock(lock_name, &block)
|
196
205
|
lock_key = @ns + '/locks/' + lock_name
|
197
206
|
current_time = get_current_time
|
198
207
|
expiry = current_time + LOCK_TIMEOUT * 1000 + 1
|
199
|
-
|
208
|
+
|
200
209
|
release_lock = lambda do
|
201
210
|
@redis.del(lock_key) if get_current_time < expiry
|
202
211
|
end
|
203
|
-
|
212
|
+
|
204
213
|
@redis.setnx(lock_key, expiry) do |set|
|
205
214
|
next block.call(release_lock) if set == 1
|
206
|
-
|
215
|
+
|
207
216
|
@redis.get(lock_key) do |timeout|
|
208
217
|
next unless timeout
|
209
|
-
|
218
|
+
|
210
219
|
lock_timeout = timeout.to_i(10)
|
211
220
|
next if current_time < lock_timeout
|
212
|
-
|
221
|
+
|
213
222
|
@redis.getset(lock_key, expiry) do |old_value|
|
214
223
|
block.call(release_lock) if old_value == timeout
|
215
224
|
end
|
216
225
|
end
|
217
226
|
end
|
218
227
|
end
|
219
|
-
|
228
|
+
|
220
229
|
end
|
221
230
|
end
|
222
231
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faye-redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
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:
|
12
|
+
date: 2013-04-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,21 +21,31 @@ dependencies:
|
|
21
21
|
version: 0.12.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.12.0
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: em-hiredis
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
31
36
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.0
|
37
|
+
version: 0.2.0
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.2.0
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: yajl-ruby
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,18 +53,28 @@ dependencies:
|
|
43
53
|
version: 1.0.0
|
44
54
|
type: :runtime
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rspec
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
|
-
- -
|
67
|
+
- - ! '>='
|
53
68
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
69
|
+
version: '0'
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
58
78
|
description:
|
59
79
|
email: jcoglan@gmail.com
|
60
80
|
executables: []
|
@@ -63,9 +83,7 @@ extra_rdoc_files:
|
|
63
83
|
- README.rdoc
|
64
84
|
files:
|
65
85
|
- README.rdoc
|
66
|
-
-
|
67
|
-
- spec/faye_redis_spec.rb
|
68
|
-
- spec/spec_helper.rb
|
86
|
+
- CHANGELOG.txt
|
69
87
|
- lib/faye/redis.rb
|
70
88
|
homepage: http://github.com/faye/faye-redis-ruby
|
71
89
|
licenses: []
|
@@ -89,8 +107,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
107
|
version: '0'
|
90
108
|
requirements: []
|
91
109
|
rubyforge_project:
|
92
|
-
rubygems_version: 1.8.
|
110
|
+
rubygems_version: 1.8.23
|
93
111
|
signing_key:
|
94
112
|
specification_version: 3
|
95
113
|
summary: Redis backend engine for Faye
|
96
114
|
test_files: []
|
115
|
+
has_rdoc:
|
data/spec/faye_redis_spec.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Faye::Redis do
|
4
|
-
let(:engine_opts) do
|
5
|
-
pw = ENV["TRAVIS"] ? nil : "foobared"
|
6
|
-
{:type => Faye::Redis, :password => pw, :namespace => Time.now.to_i.to_s}
|
7
|
-
end
|
8
|
-
|
9
|
-
after do
|
10
|
-
engine.disconnect
|
11
|
-
redis = EM::Hiredis::Client.connect('localhost', 6379)
|
12
|
-
redis.auth(engine_opts[:password])
|
13
|
-
redis.flushall
|
14
|
-
end
|
15
|
-
|
16
|
-
it_should_behave_like "faye engine"
|
17
|
-
it_should_behave_like "distributed engine"
|
18
|
-
|
19
|
-
next if ENV["TRAVIS"]
|
20
|
-
|
21
|
-
describe "using a Unix socket" do
|
22
|
-
before { engine_opts[:socket] = "/tmp/redis.sock" }
|
23
|
-
it_should_behave_like "faye engine"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
data/spec/redis.conf
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
daemonize no
|
2
|
-
pidfile /tmp/redis.pid
|
3
|
-
port 6379
|
4
|
-
unixsocket /tmp/redis.sock
|
5
|
-
timeout 300
|
6
|
-
loglevel verbose
|
7
|
-
logfile stdout
|
8
|
-
databases 16
|
9
|
-
|
10
|
-
save 900 1
|
11
|
-
save 300 10
|
12
|
-
save 60 10000
|
13
|
-
|
14
|
-
rdbcompression yes
|
15
|
-
dbfilename dump.rdb
|
16
|
-
dir ./
|
17
|
-
|
18
|
-
slave-serve-stale-data yes
|
19
|
-
|
20
|
-
requirepass foobared
|
21
|
-
|
22
|
-
appendonly no
|
23
|
-
appendfsync everysec
|
24
|
-
no-appendfsync-on-rewrite no
|
25
|
-
|
26
|
-
vm-enabled no
|
27
|
-
vm-swap-file /tmp/redis.swap
|
28
|
-
vm-max-memory 0
|
29
|
-
vm-page-size 32
|
30
|
-
vm-pages 134217728
|
31
|
-
vm-max-threads 4
|
32
|
-
|
33
|
-
hash-max-zipmap-entries 512
|
34
|
-
hash-max-zipmap-value 64
|
35
|
-
|
36
|
-
list-max-ziplist-entries 512
|
37
|
-
list-max-ziplist-value 64
|
38
|
-
|
39
|
-
set-max-intset-entries 512
|
40
|
-
|
41
|
-
activerehashing yes
|
42
|
-
|
data/spec/spec_helper.rb
DELETED