Skip to content

Commit 234ce6c

Browse files
author
Rory Low
committed
2 parents d53942f + 1c1eaec commit 234ce6c

File tree

10 files changed

+93
-24
lines changed

10 files changed

+93
-24
lines changed

Gemfile.lock

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ PATH
88
rack
99
rails
1010
redis
11+
redis-objects
1112
thin
1213

1314
GEM
@@ -41,7 +42,7 @@ GEM
4142
multi_json (~> 1.3)
4243
thread_safe (~> 0.1)
4344
tzinfo (~> 0.3.37)
44-
arel (4.0.0)
45+
arel (4.0.1)
4546
atomic (1.1.10)
4647
atomic (1.1.10-java)
4748
builder (3.1.4)
@@ -100,7 +101,7 @@ GEM
100101
mime-types (~> 1.16)
101102
treetop (~> 1.4.8)
102103
method_source (0.8.1)
103-
mime-types (1.23)
104+
mime-types (1.25)
104105
minitest (4.7.5)
105106
multi_json (1.7.7)
106107
polyglot (0.3.3)
@@ -135,7 +136,9 @@ GEM
135136
ffi (>= 0.5.0)
136137
rb-kqueue (0.2.0)
137138
ffi (>= 0.5.0)
138-
redis (3.0.4)
139+
redis (3.0.5)
140+
redis-objects (0.7.0)
141+
redis (>= 3.0.2)
139142
ref (1.0.5)
140143
rspec (2.13.0)
141144
rspec-core (~> 2.13.0)
@@ -172,7 +175,7 @@ GEM
172175
multi_json (~> 1.0)
173176
rack (~> 1.0)
174177
tilt (~> 1.1, != 1.3.0)
175-
sprockets-rails (2.0.0)
178+
sprockets-rails (2.0.1)
176179
actionpack (>= 3.0)
177180
activesupport (>= 3.0)
178181
sprockets (~> 2.8)
@@ -191,7 +194,7 @@ GEM
191194
thread_safe (0.1.0)
192195
atomic
193196
tilt (1.4.1)
194-
treetop (1.4.14)
197+
treetop (1.4.15)
195198
polyglot
196199
polyglot (>= 0.3.1)
197200
tzinfo (0.3.37)

lib/websocket_rails/channel.rb

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ class Channel
55

66
delegate :config, :channel_tokens, :channel_manager, :to => WebsocketRails
77

8-
attr_reader :name, :subscribers, :token
8+
attr_reader :name, :subscribers
99

1010
def initialize(channel_name)
1111
@subscribers = []
1212
@name = channel_name
1313
@private = false
14-
@token = generate_unique_token
1514
end
1615

1716
def subscribe(connection)
@@ -39,7 +38,7 @@ def trigger(event_name,data={},options={})
3938
end
4039

4140
def trigger_event(event)
42-
return if event.token != @token
41+
return if event.token != token
4342
info "[#{name}] #{event.data.inspect}"
4443
send_data event
4544
end
@@ -55,20 +54,24 @@ def is_private?
5554
@private
5655
end
5756

57+
def token
58+
@token ||= channel_tokens[@name] ||= generate_unique_token
59+
end
60+
5861
private
5962

6063
def generate_unique_token
6164
begin
62-
token = SecureRandom.urlsafe_base64
63-
end while channel_tokens.include?(token)
65+
new_token = SecureRandom.uuid
66+
end while channel_tokens.values.include?(new_token)
6467

65-
token
68+
new_token
6669
end
6770

6871
def send_token(connection)
6972
options = {
7073
:channel => @name,
71-
:data => {:token => @token},
74+
:data => {:token => token},
7275
:connection => connection
7376
}
7477
info 'sending token'

lib/websocket_rails/channel_manager.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'redis-objects'
2+
13
module WebsocketRails
24

35
class << self
@@ -18,11 +20,20 @@ def channel_tokens
1820

1921
class ChannelManager
2022

21-
attr_reader :channels, :channel_tokens
23+
attr_reader :channels
2224

2325
def initialize
2426
@channels = {}.with_indifferent_access
25-
@channel_tokens = []
27+
end
28+
29+
def channel_tokens
30+
@channel_tokens ||= begin
31+
if WebsocketRails.synchronize?
32+
::Redis::HashKey.new('websocket_rails.channel_tokens', Synchronization.redis)
33+
else
34+
{}
35+
end
36+
end
2637
end
2738

2839
def [](channel)

lib/websocket_rails/event.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def as_json
126126
:data => data,
127127
:success => success,
128128
:result => result,
129+
:token => token,
129130
:server_token => server_token
130131
}
131132
]

lib/websocket_rails/synchronization.rb

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,21 @@ def self.shutdown!
3333
singleton.shutdown!
3434
end
3535

36+
def self.redis
37+
singleton.redis
38+
end
39+
3640
def self.singleton
3741
@singleton ||= new
3842
end
3943

4044
include Logging
4145

4246
def redis
43-
@redis ||= Redis.new(WebsocketRails.config.redis_options)
47+
@redis ||= begin
48+
redis_options = WebsocketRails.config.redis_options
49+
EM.reactor_running? ? Redis.new(redis_options) : ruby_redis
50+
end
4451
end
4552

4653
def ruby_redis
@@ -52,9 +59,8 @@ def ruby_redis
5259

5360
def publish(event)
5461
Fiber.new do
55-
redis_client = EM.reactor_running? ? redis : ruby_redis
5662
event.server_token = server_token
57-
redis_client.publish "websocket_rails.events", event.serialize
63+
redis.publish "websocket_rails.events", event.serialize
5864
end.resume
5965
end
6066

@@ -157,16 +163,14 @@ def destroy_user(identifier)
157163

158164
def find_user(identifier)
159165
Fiber.new do
160-
redis_client = EM.reactor_running? ? redis : ruby_redis
161-
raw_user = redis_client.hget('websocket_rails.users', identifier)
166+
raw_user = redis.hget('websocket_rails.users', identifier)
162167
raw_user ? JSON.parse(raw_user) : nil
163168
end.resume
164169
end
165170

166171
def all_users
167172
Fiber.new do
168-
redis_client = EM.reactor_running? ? redis : ruby_redis
169-
redis_client.hgetall('websocket_rails.users')
173+
redis.hgetall('websocket_rails.users')
170174
end.resume
171175
end
172176

spec/unit/channel_manager_spec.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,29 @@ module WebsocketRails
1515
end
1616
end
1717

18+
describe ".channel_tokens" do
19+
it "should delegate to channel manager" do
20+
ChannelManager.any_instance.should_receive(:channel_tokens)
21+
WebsocketRails.channel_tokens
22+
end
23+
end
24+
1825
describe ChannelManager do
1926

27+
describe "#channel_tokens" do
28+
it "should return a Hash-like" do
29+
subject.channel_tokens.respond_to? :[]
30+
subject.channel_tokens.respond_to? :has_key?
31+
end
32+
33+
it 'is used to store Channel\'s token' do
34+
ChannelManager.any_instance.should_receive(:channel_tokens)
35+
.at_least(:twice).and_call_original
36+
token = Channel.new(:my_new_test_channel).token
37+
WebsocketRails.channel_tokens[:my_new_test_channel].should == token
38+
end
39+
end
40+
2041
describe "#[]" do
2142
context "accessing a channel" do
2243
it "should create the channel if it does not exist" do

spec/unit/channel_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,21 @@ module WebsocketRails
128128
subject.is_private?.should_not be_true
129129
end
130130
end
131+
132+
describe "#token" do
133+
it 'is long enough' do
134+
subject.token.length.should > 10
135+
end
136+
137+
it 'remains the same between two call' do
138+
subject.token.should == subject.token
139+
end
140+
141+
it 'is the same for two channels with the same name' do
142+
subject.token.should == Channel.new(subject.name).token
143+
end
144+
end
145+
131146
end
132147
end
133148
end

spec/unit/connection_adapters_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ module ConnectionAdapters
192192

193193
it "should serialize all events into one array" do
194194
serialized_array = <<-EOF.strip_heredoc
195-
[["queued_event",{"id":null,"channel":null,"user_id":null,"data":"test","success":null,"result":null,"server_token":null}],
196-
["queued_event",{"id":null,"channel":null,"user_id":null,"data":"test","success":null,"result":null,"server_token":null}]]
195+
[["queued_event",{"id":null,"channel":null,"user_id":null,"data":"test","success":null,"result":null,"token":null,"server_token":null}],
196+
["queued_event",{"id":null,"channel":null,"user_id":null,"data":"test","success":null,"result":null,"token":null,"server_token":null}]]
197197
EOF
198198

199199
subject.should_receive(:send).with(serialized_array.gsub(/\n/,'').strip)

spec/unit/event_spec.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module WebsocketRails
66
let(:encoded_message_string) { '["new_message",{"id":"1234","data":"this is a message"}]' }
77
let(:namespace_encoded_message_string) { '["product.new_message",{"id":"1234","data":"this is a message"}]' }
88
let(:namespace_encoded_message) { '["product.new_message",{"id":"1234","data":{"message":"this is a message"}}]' }
9-
let(:channel_encoded_message_string) { '["new_message",{"id":"1234","channel":"awesome_channel","user_id":null,"data":"this is a message","success":null,"result":null,"server_token":"1234"}]' }
9+
let(:channel_encoded_message_string) { '["new_message",{"id":"1234","channel":"awesome_channel","user_id":null,"data":"this is a message","success":null,"result":null,"token":null,"server_token":"1234"}]' }
1010
let(:synchronizable_encoded_message) { '["new_message",{"id":"1234","data":{"message":"this is a message"},"server_token":"1234"}]' }
1111
let(:connection) { double('connection') }
1212

@@ -151,6 +151,16 @@ module WebsocketRails
151151
data[1]['server_token'].should == '1234'
152152
end
153153
end
154+
155+
describe "#as_json" do
156+
it "returns a Hash representation of the Event" do
157+
hash = { data: { 'test' => 'test'}, channel: :awesome_channel }
158+
event = Event.new 'test', hash
159+
event.as_json[0].should == :test
160+
event.as_json[1][:data].should == hash[:data]
161+
event.as_json[1][:channel].should == hash[:channel]
162+
end
163+
end
154164
end
155165

156166
end

websocket-rails.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
2525
s.add_dependency "redis"
2626
s.add_dependency "hiredis"
2727
s.add_dependency "em-synchrony"
28+
s.add_dependency "redis-objects"
2829
s.add_development_dependency "rake"
2930
s.add_development_dependency "rspec-rails"
3031
s.add_development_dependency 'rspec-matchers-matchers'

0 commit comments

Comments
 (0)