faye-redis 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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