celluloid_pubsub 0.1.0 → 0.2.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.
- 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
|