celluloid_pubsub 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -2
- data/celluloid_pubsub.gemspec +2 -0
- data/examples/redis_test.rb +2 -0
- data/examples/shared_classes.rb +92 -0
- data/examples/simple_test.rb +2 -65
- data/lib/celluloid_pubsub.rb +1 -0
- data/lib/celluloid_pubsub/{client_pubsub.rb → client.rb} +22 -11
- data/lib/celluloid_pubsub/reactor.rb +27 -20
- data/lib/celluloid_pubsub/redis.rb +25 -0
- data/lib/celluloid_pubsub/redis_reactor.rb +78 -0
- data/lib/celluloid_pubsub/version.rb +1 -1
- data/lib/celluloid_pubsub/web_server.rb +34 -12
- metadata +47 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4ee6c97f0f5d1bcda519f4670ab5b885c4751bd
|
4
|
+
data.tar.gz: a996759005640ed3bd498cb8b20c0624e078253d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f09f7ac3c17117442b84efe1ba90a2d739e4228152d647eba7b31ed3c7caf5888f1a04038514aaf766d9d7944c573ef25023642ad07314f532c4f973969ee64e
|
7
|
+
data.tar.gz: 4778aa4bab829487290694cf2d4bd6b5f26ae5f307e60474e4c299d43c316f644988685ddef4f8455c906abe9ddd492db1c39790a8b1a8a52f8bb50b83407e08
|
data/.gitignore
CHANGED
data/celluloid_pubsub.gemspec
CHANGED
@@ -22,6 +22,8 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_runtime_dependency 'http', '~> 0.9.8', '>= 0.9.8' # TODO: remove this once fixed in reel gem ( waiting for version 0.6.0 of reel to be stable)
|
23
23
|
s.add_runtime_dependency 'celluloid-websocket-client', '~> 0.0', '>= 0.0.1'
|
24
24
|
s.add_runtime_dependency 'activesupport', '~> 4.1', '>= 4.1.0'
|
25
|
+
s.add_runtime_dependency 'em-hiredis', '~> 0.3', '>= 0.3.0'
|
26
|
+
s.add_runtime_dependency 'json', '~> 1.8', '>= 1.8.3'
|
25
27
|
|
26
28
|
s.add_development_dependency 'rspec-rails', '~> 3.3', '>= 3.3'
|
27
29
|
s.add_development_dependency 'guard', '~> 2.13', '>= 2.13'
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'celluloid_pubsub'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
debug_enabled = ENV['DEBUG'].present? && ENV['DEBUG'].to_s == 'true'
|
6
|
+
|
7
|
+
if debug_enabled == true
|
8
|
+
log_file_path = File.join(File.expand_path(File.dirname(__FILE__)), 'log', 'celluloid_pubsub.log')
|
9
|
+
puts log_file_path
|
10
|
+
FileUtils.mkdir_p(File.dirname(log_file_path))
|
11
|
+
log_file = File.open(log_file_path, 'w')
|
12
|
+
log_file.sync = true
|
13
|
+
Celluloid.logger = ::Logger.new(log_file_path)
|
14
|
+
Celluloid.task_class = Celluloid::TaskThread
|
15
|
+
Celluloid.exception_handler do |ex|
|
16
|
+
unless ex.is_a?(Interrupt)
|
17
|
+
puts ex
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# actor that subscribes to a channel
|
23
|
+
class Subscriber
|
24
|
+
include Celluloid
|
25
|
+
include Celluloid::Logger
|
26
|
+
finalizer :shutdown
|
27
|
+
|
28
|
+
def initialize(options = {})
|
29
|
+
@client = CelluloidPubsub::Client.new({ actor: Actor.current, channel: 'test_channel' }.merge(options))
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_message(message)
|
33
|
+
if @client.succesfull_subscription?(message)
|
34
|
+
puts "subscriber got successful subscription #{message.inspect}"
|
35
|
+
@client.publish('test_channel2', 'data' => ' subscriber got successfull subscription') # the message needs to be a Hash
|
36
|
+
else
|
37
|
+
puts "subscriber got message #{message.inspect}"
|
38
|
+
@client.unsubscribe('test_channel')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_close(code, reason)
|
43
|
+
puts "websocket connection closed: #{code.inspect}, #{reason.inspect}"
|
44
|
+
terminate
|
45
|
+
end
|
46
|
+
def shutdown
|
47
|
+
debug "#{self.class} tries to 'shudown'"
|
48
|
+
terminate
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# actor that publishes a message in a channel
|
53
|
+
class Publisher
|
54
|
+
include Celluloid
|
55
|
+
include Celluloid::Logger
|
56
|
+
finalizer :shutdown
|
57
|
+
|
58
|
+
def initialize(options = {})
|
59
|
+
@client = CelluloidPubsub::Client.new({ actor: Actor.current, channel: 'test_channel2' }.merge(options))
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_message(message)
|
63
|
+
puts " publisher got #{message.inspect}"
|
64
|
+
@client.publish('test_channel', 'data' => 'my_message') # the message needs to be a Hash
|
65
|
+
@client.unsubscribe('test_channel2')
|
66
|
+
end
|
67
|
+
|
68
|
+
def on_close(code, reason)
|
69
|
+
puts "websocket connection closed: #{code.inspect}, #{reason.inspect}"
|
70
|
+
terminate
|
71
|
+
end
|
72
|
+
def shutdown
|
73
|
+
debug "#{self.class} tries to 'shudown'"
|
74
|
+
terminate
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
CelluloidPubsub::WebServer.supervise_as(:web_server, enable_debug: debug_enabled, use_redis: $use_redis)
|
79
|
+
Subscriber.supervise_as(:subscriber, enable_debug: debug_enabled)
|
80
|
+
Publisher.supervise_as(:publisher, enable_debug: debug_enabled)
|
81
|
+
signal_received = false
|
82
|
+
|
83
|
+
at_exit do
|
84
|
+
Celluloid.shutdown
|
85
|
+
end
|
86
|
+
Signal.trap('INT') do
|
87
|
+
puts "\nAn interrupt signal is happening!"
|
88
|
+
signal_received = true
|
89
|
+
end
|
90
|
+
|
91
|
+
sleep 0.1 until signal_received
|
92
|
+
puts 'Exited succesfully! =)'
|
data/examples/simple_test.rb
CHANGED
@@ -1,65 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'logger'
|
4
|
-
|
5
|
-
debug_enabled = ENV['DEBUG'].present? && ENV['DEBUG'].to_s == 'true'
|
6
|
-
|
7
|
-
if debug_enabled == true
|
8
|
-
log_file_path = File.join(File.expand_path(File.dirname(__FILE__)), 'log', 'celluloid_pubsub.log')
|
9
|
-
puts log_file_path
|
10
|
-
FileUtils.mkdir_p(File.dirname(log_file_path))
|
11
|
-
log_file = File.open(log_file_path, 'w')
|
12
|
-
log_file.sync = true
|
13
|
-
Celluloid.logger = ::Logger.new(log_file_path)
|
14
|
-
end
|
15
|
-
|
16
|
-
# actor that subscribes to a channel
|
17
|
-
class Subscriber
|
18
|
-
include Celluloid
|
19
|
-
include Celluloid::Logger
|
20
|
-
|
21
|
-
def initialize(options = {})
|
22
|
-
@client = CelluloidPubsub::Client.new({ actor: Actor.current, channel: 'test_channel' }.merge(options))
|
23
|
-
end
|
24
|
-
|
25
|
-
def on_message(message)
|
26
|
-
if @client.succesfull_subscription?(message)
|
27
|
-
puts "subscriber got successful subscription #{message.inspect}"
|
28
|
-
@client.publish('test_channel2', 'data' => ' subscriber got successfull subscription') # the message needs to be a Hash
|
29
|
-
else
|
30
|
-
puts "subscriber got message #{message.inspect}"
|
31
|
-
@client.unsubscribe('test_channel')
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def on_close(code, reason)
|
36
|
-
puts "websocket connection closed: #{code.inspect}, #{reason.inspect}"
|
37
|
-
terminate
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# actor that publishes a message in a channel
|
42
|
-
class Publisher
|
43
|
-
include Celluloid
|
44
|
-
include Celluloid::Logger
|
45
|
-
|
46
|
-
def initialize(options = {})
|
47
|
-
@client = CelluloidPubsub::Client.new({ actor: Actor.current, channel: 'test_channel2' }.merge(options))
|
48
|
-
@client.publish('test_channel', 'data' => 'my_message') # the message needs to be a Hash
|
49
|
-
end
|
50
|
-
|
51
|
-
def on_message(message)
|
52
|
-
puts " publisher got #{message.inspect}"
|
53
|
-
@client.unsubscribe('test_channel2')
|
54
|
-
end
|
55
|
-
|
56
|
-
def on_close(code, reason)
|
57
|
-
puts "websocket connection closed: #{code.inspect}, #{reason.inspect}"
|
58
|
-
terminate
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
CelluloidPubsub::WebServer.supervise_as(:web_server, enable_debug: debug_enabled)
|
63
|
-
Subscriber.supervise_as(:subscriber, enable_debug: debug_enabled)
|
64
|
-
Publisher.supervise_as(:publisher, enable_debug: debug_enabled)
|
65
|
-
sleep
|
1
|
+
$use_redis = false
|
2
|
+
require_relative './shared_classes'
|
data/lib/celluloid_pubsub.rb
CHANGED
@@ -27,7 +27,7 @@ module CelluloidPubsub
|
|
27
27
|
include Celluloid
|
28
28
|
include Celluloid::Logger
|
29
29
|
attr_accessor :actor, :client, :options, :hostname, :port, :path, :channel
|
30
|
-
|
30
|
+
finalizer :shutdown
|
31
31
|
# receives a list of options that are used to connect to the webserver and an actor to which the callbacks are delegated to
|
32
32
|
# when receiving messages from a channel
|
33
33
|
#
|
@@ -46,7 +46,20 @@ module CelluloidPubsub
|
|
46
46
|
parse_options(options)
|
47
47
|
raise "#{self}: Please provide an actor in the options list!!!" if @actor.blank?
|
48
48
|
raise "#{self}: Please provide an channel in the options list!!!" if @channel.blank?
|
49
|
+
@actor.link Actor.current if @actor.respond_to?(:link)
|
49
50
|
@client = Celluloid::WebSocket::Client.new("ws://#{@hostname}:#{@port}#{@path}", Actor.current)
|
51
|
+
Actor.current.link @client
|
52
|
+
end
|
53
|
+
|
54
|
+
# the method will terminate the current actor
|
55
|
+
#
|
56
|
+
#
|
57
|
+
# @return [void]
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
def shutdown
|
61
|
+
debug "#{self.class} tries to 'shudown'" if debug_enabled?
|
62
|
+
terminate
|
50
63
|
end
|
51
64
|
|
52
65
|
# check the options list for values and sets default values if not found
|
@@ -88,9 +101,8 @@ module CelluloidPubsub
|
|
88
101
|
#
|
89
102
|
# @api public
|
90
103
|
def subscribe(channel)
|
91
|
-
|
92
|
-
|
93
|
-
async.chat(subscription_data)
|
104
|
+
debug("#{@actor.class} tries to subscribe to channel #{channel}") if debug_enabled?
|
105
|
+
async.send_action('subscribe', channel)
|
94
106
|
end
|
95
107
|
|
96
108
|
# checks if the message has the successfull subscription action
|
@@ -153,7 +165,7 @@ module CelluloidPubsub
|
|
153
165
|
#
|
154
166
|
# @api public
|
155
167
|
def on_open
|
156
|
-
debug("#{
|
168
|
+
debug("#{@actor.class} websocket connection opened") if debug_enabled?
|
157
169
|
async.subscribe(@channel)
|
158
170
|
end
|
159
171
|
|
@@ -167,9 +179,9 @@ module CelluloidPubsub
|
|
167
179
|
#
|
168
180
|
# @api public
|
169
181
|
def on_message(data)
|
170
|
-
debug("#{
|
182
|
+
debug("#{@actor.class} received plain #{data}") if debug_enabled?
|
171
183
|
message = JSON.parse(data)
|
172
|
-
debug("#{
|
184
|
+
debug("#{@actor.class} received JSON #{message}") if debug_enabled?
|
173
185
|
@actor.async.on_message(message)
|
174
186
|
end
|
175
187
|
|
@@ -185,7 +197,7 @@ module CelluloidPubsub
|
|
185
197
|
def on_close(code, reason)
|
186
198
|
@client.terminate
|
187
199
|
terminate
|
188
|
-
debug("#{
|
200
|
+
debug("#{@actor.class} dispatching on close #{code} #{reason}") if debug_enabled?
|
189
201
|
@actor.async.on_close(code, reason)
|
190
202
|
end
|
191
203
|
|
@@ -204,7 +216,6 @@ module CelluloidPubsub
|
|
204
216
|
publishing_data = { 'client_action' => action }
|
205
217
|
publishing_data = publishing_data.merge('channel' => channel) if channel.present?
|
206
218
|
publishing_data = publishing_data.merge('data' => data) if data.present?
|
207
|
-
debug(" #{self.class} sends: #{publishing_data}") if debug_enabled?
|
208
219
|
async.chat(publishing_data)
|
209
220
|
end
|
210
221
|
|
@@ -221,10 +232,10 @@ module CelluloidPubsub
|
|
221
232
|
final_message = nil
|
222
233
|
if message.is_a?(Hash)
|
223
234
|
final_message = message.to_json
|
224
|
-
debug("#{
|
235
|
+
debug("#{@actor.class} sends #{message.to_json}") if debug_enabled?
|
225
236
|
else
|
226
237
|
final_message = JSON.dump(action: 'message', message: message)
|
227
|
-
debug("#{
|
238
|
+
debug("#{@actor.class} sends JSON #{final_message}") if debug_enabled?
|
228
239
|
end
|
229
240
|
@client.text final_message
|
230
241
|
end
|
@@ -18,7 +18,7 @@ module CelluloidPubsub
|
|
18
18
|
include Celluloid::Logger
|
19
19
|
|
20
20
|
attr_accessor :websocket, :server, :channels
|
21
|
-
|
21
|
+
finalizer :shutdown
|
22
22
|
# rececives a new socket connection from the server
|
23
23
|
# and listens for messages
|
24
24
|
#
|
@@ -31,7 +31,7 @@ module CelluloidPubsub
|
|
31
31
|
@server = server
|
32
32
|
@channels = []
|
33
33
|
@websocket = websocket
|
34
|
-
info "Streaming changes for #{websocket.url}" if @server.debug_enabled?
|
34
|
+
info "#{self.class} Streaming changes for #{websocket.url}" if @server.debug_enabled?
|
35
35
|
async.run
|
36
36
|
end
|
37
37
|
|
@@ -63,7 +63,7 @@ module CelluloidPubsub
|
|
63
63
|
begin
|
64
64
|
message = @websocket.read
|
65
65
|
rescue => e
|
66
|
-
debug(e)
|
66
|
+
debug(e)
|
67
67
|
end
|
68
68
|
message
|
69
69
|
end
|
@@ -78,12 +78,12 @@ module CelluloidPubsub
|
|
78
78
|
#
|
79
79
|
# @api public
|
80
80
|
def parse_json_data(message)
|
81
|
-
debug "
|
81
|
+
debug "#{self.class} read message #{message}" if @server.debug_enabled?
|
82
82
|
json_data = nil
|
83
83
|
begin
|
84
84
|
json_data = JSON.parse(message)
|
85
85
|
rescue => e
|
86
|
-
debug "
|
86
|
+
debug "#{self.class} could not parse #{message} because of #{e.inspect}" if @server.debug_enabled?
|
87
87
|
# do nothing
|
88
88
|
end
|
89
89
|
json_data = message if json_data.nil?
|
@@ -124,7 +124,7 @@ module CelluloidPubsub
|
|
124
124
|
def handle_parsed_websocket_message(json_data)
|
125
125
|
if json_data.is_a?(Hash)
|
126
126
|
json_data = json_data.stringify_keys
|
127
|
-
debug "
|
127
|
+
debug "#{self.class} finds actions for #{json_data}" if @server.debug_enabled?
|
128
128
|
delegate_action(json_data) if json_data['client_action'].present?
|
129
129
|
else
|
130
130
|
handle_unknown_action(json_data)
|
@@ -154,18 +154,18 @@ module CelluloidPubsub
|
|
154
154
|
# @api public
|
155
155
|
def delegate_action(json_data)
|
156
156
|
case json_data['client_action']
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
157
|
+
when 'unsubscribe_all'
|
158
|
+
unsubscribe_all
|
159
|
+
when 'unsubscribe_clients'
|
160
|
+
async.unsubscribe_clients(json_data['channel'])
|
161
|
+
when 'unsubscribe'
|
162
|
+
async.unsubscribe(json_data['channel'])
|
163
|
+
when 'subscribe'
|
164
|
+
async.start_subscriber(json_data['channel'], json_data)
|
165
|
+
when 'publish'
|
166
|
+
@server.publish_event(json_data['channel'], json_data['data'].to_json)
|
167
|
+
else
|
168
|
+
handle_unknown_action(json_data)
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
@@ -191,6 +191,7 @@ module CelluloidPubsub
|
|
191
191
|
#
|
192
192
|
# @api public
|
193
193
|
def unsubscribe(channel)
|
194
|
+
debug "#{self.class} runs 'unsubscribe' method with #{channel}" if @server.debug_enabled?
|
194
195
|
return unless channel.present?
|
195
196
|
@channels.delete(channel) unless @channels.blank?
|
196
197
|
@websocket.close if @channels.blank?
|
@@ -207,6 +208,7 @@ module CelluloidPubsub
|
|
207
208
|
#
|
208
209
|
# @api public
|
209
210
|
def unsubscribe_clients(channel)
|
211
|
+
debug "#{self.class} runs 'unsubscribe_clients' method with #{channel}" if @server.debug_enabled?
|
210
212
|
return if channel.blank? || @server.subscribers[channel].blank?
|
211
213
|
unsubscribe_from_channel(channel)
|
212
214
|
@server.subscribers[channel] = []
|
@@ -219,6 +221,7 @@ module CelluloidPubsub
|
|
219
221
|
#
|
220
222
|
# @api public
|
221
223
|
def shutdown
|
224
|
+
debug "#{self.class} tries to 'shudown'"
|
222
225
|
terminate
|
223
226
|
end
|
224
227
|
|
@@ -236,8 +239,8 @@ module CelluloidPubsub
|
|
236
239
|
def start_subscriber(channel, message)
|
237
240
|
return unless channel.present?
|
238
241
|
add_subscriber_to_channel(channel, message)
|
239
|
-
debug "
|
240
|
-
@websocket << message.merge('client_action' => 'successful_subscription', 'channel' => channel).to_json
|
242
|
+
debug "#{self.class} subscribed to #{channel} with #{message}" if @server.debug_enabled?
|
243
|
+
@websocket << message.merge('client_action' => 'successful_subscription', 'channel' => channel).to_json unless @server.redis_enabled?
|
241
244
|
end
|
242
245
|
|
243
246
|
# adds the curent actor the list of the subscribers for a particular channel
|
@@ -254,6 +257,7 @@ module CelluloidPubsub
|
|
254
257
|
CelluloidPubsub::Registry.channels << channel unless CelluloidPubsub::Registry.channels.include?(channel)
|
255
258
|
@server.subscribers[channel] ||= []
|
256
259
|
@server.subscribers[channel] << { reactor: Actor.current, message: message }
|
260
|
+
|
257
261
|
end
|
258
262
|
|
259
263
|
# unsubscribes all actors from all channels and terminates the curent actor
|
@@ -262,6 +266,7 @@ module CelluloidPubsub
|
|
262
266
|
#
|
263
267
|
# @api public
|
264
268
|
def unsubscribe_all
|
269
|
+
debug "#{self.class} runs 'unsubscribe_all' method" if @server.debug_enabled?
|
265
270
|
CelluloidPubsub::Registry.channels.map do |channel|
|
266
271
|
unsubscribe_from_channel(channel)
|
267
272
|
@server.subscribers[channel] = []
|
@@ -278,6 +283,8 @@ module CelluloidPubsub
|
|
278
283
|
#
|
279
284
|
# @api public
|
280
285
|
def unsubscribe_from_channel(channel)
|
286
|
+
debug "#{self.class} runs 'unsubscribe_from_channel' method with #{channel}" if @server.debug_enabled?
|
287
|
+
return if @server.subscribers[channel].blank?
|
281
288
|
@server.subscribers[channel].each do |hash|
|
282
289
|
hash[:reactor].websocket.close
|
283
290
|
Celluloid::Actor.kill(hash[:reactor])
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CelluloidPubsub
|
2
|
+
class Redis
|
3
|
+
class << self
|
4
|
+
@connected ||= false
|
5
|
+
attr_accessor :connected, :connection
|
6
|
+
|
7
|
+
alias_method :connected?, :connected
|
8
|
+
|
9
|
+
def connect(_options = {})
|
10
|
+
require 'eventmachine'
|
11
|
+
require 'em-hiredis'
|
12
|
+
EM.run do
|
13
|
+
@connection = EM::Hiredis.connect
|
14
|
+
@connected = true
|
15
|
+
yield @connection if block_given?
|
16
|
+
end
|
17
|
+
EM.error_handler do |error|
|
18
|
+
unless error.is_a?(Interrupt)
|
19
|
+
puts error.inspect
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative './reactor'
|
2
|
+
module CelluloidPubsub
|
3
|
+
class RedisReactor < CelluloidPubsub::Reactor
|
4
|
+
include Celluloid
|
5
|
+
include Celluloid::IO
|
6
|
+
include Celluloid::Logger
|
7
|
+
|
8
|
+
def unsubscribe(channel)
|
9
|
+
super
|
10
|
+
async.redis_action('unsubscribe', channel)
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_subscriber_to_channel(channel, message)
|
14
|
+
super
|
15
|
+
async.redis_action('subscribe', channel, message)
|
16
|
+
end
|
17
|
+
|
18
|
+
def unsubscribe_from_channel(channel)
|
19
|
+
super
|
20
|
+
async.redis_action('unsubscribe', channel)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def unsubscribe_all
|
25
|
+
CelluloidPubsub::Registry.channels.map do |channel|
|
26
|
+
async.redis_action('unsubscribe', channel)
|
27
|
+
end
|
28
|
+
info 'clearing connections'
|
29
|
+
shutdown
|
30
|
+
end
|
31
|
+
|
32
|
+
def shutdown
|
33
|
+
@channels.each do |channel|
|
34
|
+
redis_action('unsubscribe', channel)
|
35
|
+
end
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def redis_action(action, channel = nil, message = {})
|
42
|
+
CelluloidPubsub::Redis.connect do |connection|
|
43
|
+
pubsub = connection.pubsub
|
44
|
+
pubsub.on(:unsubscribe) { |channel, remaining_subscriptions|
|
45
|
+
debug [:unsubscribe_happened, channel, remaining_subscriptions].inspect if @server.debug_enabled?
|
46
|
+
}
|
47
|
+
|
48
|
+
if action == 'subscribe' && channel.present?
|
49
|
+
subscription = pubsub.subscribe(channel) {|subscribed_message|
|
50
|
+
@websocket << subscribed_message
|
51
|
+
}
|
52
|
+
subscription.callback { |reply|
|
53
|
+
@websocket << message.merge('client_action' => 'successful_subscription', 'channel' => channel, 'subscriptions' => reply).to_json
|
54
|
+
}
|
55
|
+
subscription.errback {|reply|
|
56
|
+
debug "subscription error #{reply.inspect}" if @server.debug_enabled?
|
57
|
+
}
|
58
|
+
else
|
59
|
+
if channel.present?
|
60
|
+
unsubscription = pubsub.unsubscribe(channel)
|
61
|
+
unsubscription.callback {|reply|
|
62
|
+
debug "unsubscription success #{reply.inspect}" if @server.debug_enabled?
|
63
|
+
}
|
64
|
+
unsubscription.errback {|reply|
|
65
|
+
debug "unsubscription error #{reply.inspect}" if @server.debug_enabled?
|
66
|
+
}
|
67
|
+
else
|
68
|
+
connection.unsubscribe
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -38,8 +38,8 @@ module CelluloidPubsub
|
|
38
38
|
# The request path that the webserver accepts by default
|
39
39
|
PATH = '/ws'
|
40
40
|
|
41
|
-
attr_accessor :options, :subscribers, :backlog, :hostname, :port, :path, :spy
|
42
|
-
|
41
|
+
attr_accessor :options, :subscribers, :backlog, :hostname, :port, :path, :spy, :use_redis, :debug_enabled
|
42
|
+
finalizer :shutdown
|
43
43
|
# receives a list of options that are used to configure the webserver
|
44
44
|
#
|
45
45
|
# @param [Hash] options the options that can be used to connect to webser and send additional data
|
@@ -54,11 +54,24 @@ module CelluloidPubsub
|
|
54
54
|
#
|
55
55
|
# :nocov:
|
56
56
|
def initialize(options = {})
|
57
|
+
options = options.is_a?(Array) ? options.first : options
|
57
58
|
parse_options(options)
|
58
59
|
@subscribers = {}
|
59
60
|
info "CelluloidPubsub::WebServer example starting on #{@hostname}:#{@port}" if debug_enabled?
|
60
61
|
super(@hostname, @port, { spy: @spy, backlog: @backlog }, &method(:on_connection))
|
61
62
|
end
|
63
|
+
|
64
|
+
# the method will terminate the current actor
|
65
|
+
#
|
66
|
+
#
|
67
|
+
# @return [void]
|
68
|
+
#
|
69
|
+
# @api public
|
70
|
+
def shutdown
|
71
|
+
debug "#{self.class} tries to 'shudown'"
|
72
|
+
terminate
|
73
|
+
end
|
74
|
+
|
62
75
|
# :nocov:
|
63
76
|
|
64
77
|
# receives a list of options that are used to configure the webserver
|
@@ -74,7 +87,7 @@ module CelluloidPubsub
|
|
74
87
|
#
|
75
88
|
# @api public
|
76
89
|
def parse_options(options)
|
77
|
-
|
90
|
+
options = options.is_a?(Hash) ? options : {}
|
78
91
|
@options = options.stringify_keys
|
79
92
|
debug @options if debug_enabled?
|
80
93
|
@backlog = @options.fetch('backlog', 1024)
|
@@ -82,6 +95,8 @@ module CelluloidPubsub
|
|
82
95
|
@port = @options.fetch('port', CelluloidPubsub::WebServer::PORT)
|
83
96
|
@path = @options.fetch('path', CelluloidPubsub::WebServer::PATH)
|
84
97
|
@spy = @options.fetch('spy', false)
|
98
|
+
@use_redis = @options.fetch('use_redis', false)
|
99
|
+
@debug_enabled = @options.fetch('enable_debug', false)
|
85
100
|
end
|
86
101
|
|
87
102
|
# checks if debug is enabled
|
@@ -90,7 +105,11 @@ module CelluloidPubsub
|
|
90
105
|
#
|
91
106
|
# @api public
|
92
107
|
def debug_enabled?
|
93
|
-
@
|
108
|
+
@debug_enabled.to_s == 'true'
|
109
|
+
end
|
110
|
+
|
111
|
+
def redis_enabled?
|
112
|
+
@use_redis.to_s.downcase == 'true'
|
94
113
|
end
|
95
114
|
|
96
115
|
# method for publishing data to a channel
|
@@ -102,14 +121,16 @@ module CelluloidPubsub
|
|
102
121
|
#
|
103
122
|
# @api public
|
104
123
|
def publish_event(current_topic, message)
|
105
|
-
return if current_topic.blank? || message.blank?
|
106
|
-
|
124
|
+
return if current_topic.blank? || message.blank?
|
125
|
+
if redis_enabled?
|
126
|
+
CelluloidPubsub::Redis.connection.publish(current_topic, message)
|
127
|
+
elsif @subscribers[current_topic].present?
|
107
128
|
@subscribers[current_topic].each do |hash|
|
108
129
|
hash[:reactor].websocket << message
|
109
130
|
end
|
110
|
-
rescue => e
|
111
|
-
debug("could not publish message #{message} into topic #{current_topic} because of #{e.inspect}") if debug_enabled?
|
112
131
|
end
|
132
|
+
rescue => e
|
133
|
+
debug("could not publish message #{message} into topic #{current_topic} because of #{e.inspect}") if debug_enabled?
|
113
134
|
end
|
114
135
|
|
115
136
|
# callback that will execute when receiving new conections
|
@@ -128,7 +149,7 @@ module CelluloidPubsub
|
|
128
149
|
def on_connection(connection)
|
129
150
|
while request = connection.request
|
130
151
|
if request.websocket?
|
131
|
-
info
|
152
|
+
info "#{self.class} Received a WebSocket connection" if debug_enabled?
|
132
153
|
|
133
154
|
# We're going to hand off this connection to another actor (Writer/Reader)
|
134
155
|
# However, initially Reel::Connections are "attached" to the
|
@@ -171,8 +192,8 @@ module CelluloidPubsub
|
|
171
192
|
# @api public
|
172
193
|
def route_websocket(socket)
|
173
194
|
if socket.url == @path
|
174
|
-
|
175
|
-
reactor
|
195
|
+
reactor = redis_enabled? ? CelluloidPubsub::RedisReactor.new : CelluloidPubsub::Reactor.new
|
196
|
+
info "#{reactor.class} handles new socket connection" if debug_enabled?
|
176
197
|
Actor.current.link reactor
|
177
198
|
reactor.async.work(socket, Actor.current)
|
178
199
|
else
|
@@ -191,7 +212,7 @@ module CelluloidPubsub
|
|
191
212
|
#
|
192
213
|
# @api public
|
193
214
|
def handle_dispatched_message(reactor, data)
|
194
|
-
debug "
|
215
|
+
debug "#{self.class} trying to dispatch message #{data.inspect}" if debug_enabled?
|
195
216
|
message = reactor.parse_json_data(data)
|
196
217
|
if message.present? && message.is_a?(Hash)
|
197
218
|
reactor.websocket << message.to_json
|
@@ -199,5 +220,6 @@ module CelluloidPubsub
|
|
199
220
|
reactor.websocket << data.to_json
|
200
221
|
end
|
201
222
|
end
|
223
|
+
|
202
224
|
end
|
203
225
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: celluloid_pubsub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- bogdanRada
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: celluloid
|
@@ -130,6 +130,46 @@ dependencies:
|
|
130
130
|
- - ">="
|
131
131
|
- !ruby/object:Gem::Version
|
132
132
|
version: 4.1.0
|
133
|
+
- !ruby/object:Gem::Dependency
|
134
|
+
name: em-hiredis
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0.3'
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 0.3.0
|
143
|
+
type: :runtime
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - "~>"
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0.3'
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.3.0
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: json
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '1.8'
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: 1.8.3
|
163
|
+
type: :runtime
|
164
|
+
prerelease: false
|
165
|
+
version_requirements: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - "~>"
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '1.8'
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 1.8.3
|
133
173
|
- !ruby/object:Gem::Dependency
|
134
174
|
name: rspec-rails
|
135
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -470,11 +510,15 @@ files:
|
|
470
510
|
- README.md
|
471
511
|
- Rakefile
|
472
512
|
- celluloid_pubsub.gemspec
|
513
|
+
- examples/redis_test.rb
|
514
|
+
- examples/shared_classes.rb
|
473
515
|
- examples/simple_test.rb
|
474
516
|
- init.rb
|
475
517
|
- lib/celluloid_pubsub.rb
|
476
|
-
- lib/celluloid_pubsub/
|
518
|
+
- lib/celluloid_pubsub/client.rb
|
477
519
|
- lib/celluloid_pubsub/reactor.rb
|
520
|
+
- lib/celluloid_pubsub/redis.rb
|
521
|
+
- lib/celluloid_pubsub/redis_reactor.rb
|
478
522
|
- lib/celluloid_pubsub/registry.rb
|
479
523
|
- lib/celluloid_pubsub/version.rb
|
480
524
|
- lib/celluloid_pubsub/web_server.rb
|