celluloid_pubsub 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4ee6c97f0f5d1bcda519f4670ab5b885c4751bd
4
- data.tar.gz: a996759005640ed3bd498cb8b20c0624e078253d
3
+ metadata.gz: 6aad68d75f135124f475c703d0950b1bc0b45e2c
4
+ data.tar.gz: 5e47b790b66d01dc32af3313ec54bb7ba09c8208
5
5
  SHA512:
6
- metadata.gz: f09f7ac3c17117442b84efe1ba90a2d739e4228152d647eba7b31ed3c7caf5888f1a04038514aaf766d9d7944c573ef25023642ad07314f532c4f973969ee64e
7
- data.tar.gz: 4778aa4bab829487290694cf2d4bd6b5f26ae5f307e60474e4c299d43c316f644988685ddef4f8455c906abe9ddd492db1c39790a8b1a8a52f8bb50b83407e08
6
+ metadata.gz: c33c34fab870f68825fd75b42917b556880172b7dbb64108f64a94ed1fcd067980e984715be8118d936fbdb999b105d03c8aa85c1bd26efe2093caa9f56f73bc
7
+ data.tar.gz: 885da36eee95bce09adb0c7e6644d8a53691c87b622355de60b9d94b98757ee14a87360ca48812ed757836e29762cf095c4bdec6585602cae58951e0a41badde
data/.reek ADDED
@@ -0,0 +1,11 @@
1
+ ---
2
+ Attribute:
3
+ enabled: false
4
+ TooManyInstanceVariables:
5
+ enabled: false
6
+ TooManyMethods:
7
+ enabled: false
8
+ UtilityFunction:
9
+ enabled: false
10
+ exclude_paths:
11
+ - examples
data/.rubocop.yml CHANGED
@@ -4,7 +4,11 @@ AllCops:
4
4
  - bin/**/*
5
5
  - Guardfile
6
6
  - vendor/**/*
7
+ - examples/**/*
7
8
 
9
+ ClassLength:
10
+ Max: 500
11
+
8
12
  Documentation:
9
13
  Enabled: true
10
14
 
data/Rakefile CHANGED
@@ -10,13 +10,6 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
10
10
  spec.rspec_opts = ['--backtrace', '--fail-fast'] if ENV['DEBUG']
11
11
  end
12
12
 
13
- # desc "Prepare dummy application"
14
- # task :prepare do
15
- # ENV["RAILS_ENV"] ||= 'test'
16
- # require File.expand_path("./spec/dummy/config/environment", File.dirname(__FILE__))
17
- # Dummy::Application.load_tasks
18
- # Rake::Task["db:test:prepare"].invoke
19
- # end
20
13
  YARD::Config.options[:load_plugins] = true
21
14
  YARD::Config.load_plugins
22
15
 
@@ -26,31 +19,18 @@ YARD::Rake::YardocTask.new do |t|
26
19
  t.stats_options = ['--list-undoc'] # optional
27
20
  end
28
21
 
29
- unless ENV['TRAVIS']
30
- require 'rvm-tester'
31
- RVM::Tester::TesterTask.new(:suite) do |t|
32
- t.rubies = %w(1.9.3 2.0.0 2.1.0) # which versions to test (required!)
33
- t.bundle_install = true # updates Gemfile.lock, default is true
34
- t.use_travis = true # looks for Rubies in .travis.yml (on by default)
35
- t.command = 'bundle exec rake' # runs plain "rake" by default
36
- t.env = { 'VERBOSE' => '1', 'RAILS_ENV' => 'test', 'RACK_ENV' => 'test' } # set any ENV vars
37
- t.num_workers = 5 # defaults to 3
38
- t.verbose = true # shows more output, off by default
39
- end
40
- end
41
-
42
22
  desc 'Default: run the unit tests.'
43
23
  task default: [:all]
44
24
 
45
25
  desc 'Test the plugin under all supported Rails versions.'
46
26
  task :all do |_t|
47
27
  if ENV['TRAVIS']
48
- exec(' bundle exec phare && bundle exec rake spec && bundle exec rake coveralls:push')
28
+ exec(' bundle exec rubocop . && bundle exec rake spec && bundle exec rake coveralls:push')
49
29
  else
50
- exec('bundle exec rubocop -a . && bundle exec phare && bundle exec rake spec')
30
+ exec('bundle exec rubocop -a . && bundle exec reek . && bundle exec rake spec')
51
31
  end
52
32
  end
53
33
 
54
34
  task :docs do
55
- exec(' bundle exec rubocop -a . && bundle exec phare && bundle exec inch --pedantic && bundle exec yard')
35
+ exec(' bundle exec rubocop -a . && bundle exec reek . && bundle exec inch --pedantic && bundle exec yard')
56
36
  end
@@ -26,20 +26,16 @@ Gem::Specification.new do |s|
26
26
  s.add_runtime_dependency 'json', '~> 1.8', '>= 1.8.3'
27
27
 
28
28
  s.add_development_dependency 'rspec-rails', '~> 3.3', '>= 3.3'
29
- s.add_development_dependency 'guard', '~> 2.13', '>= 2.13'
30
- s.add_development_dependency 'guard-rspec', '~> 4.6', '>= 4.6'
31
29
  s.add_development_dependency 'simplecov', '~> 0.10', '>= 0.10'
32
30
  s.add_development_dependency 'simplecov-summary', '~> 0.0.4', '>= 0.0.4'
33
31
  s.add_development_dependency 'mocha', '~> 1.1', '>= 1.1'
34
32
  s.add_development_dependency 'coveralls', '~> 0.7', '>= 0.7'
35
- s.add_development_dependency 'rvm-tester', '~> 1.1', '>= 1.1'
36
33
 
37
34
  s.add_development_dependency 'rubocop', '~> 0.33', '>= 0.33'
38
- s.add_development_dependency 'phare', '~> 0.7', '>= 0.7'
35
+ s.add_development_dependency 'reek', '~> 3.8', '>= 3.8.1'
39
36
  s.add_development_dependency 'yard', '~> 0.8', '>= 0.8.7'
40
37
  s.add_development_dependency 'yard-rspec', '~> 0.1', '>= 0.1'
41
38
  s.add_development_dependency 'redcarpet', '~> 3.3', '>= 3.3'
42
39
  s.add_development_dependency 'github-markup', '~> 1.3', '>= 1.3.3'
43
40
  s.add_development_dependency 'inch', '~> 0.6', '>= 0.6'
44
- s.add_development_dependency 'guard-inch', '~> 0.1', '>= 0.1.0'
45
41
  end
@@ -1,2 +1,2 @@
1
- $use_redis = true
1
+ ENV['USE_REDIS'] = 'true'
2
2
  require_relative './shared_classes'
@@ -3,27 +3,14 @@ require 'celluloid_pubsub'
3
3
  require 'logger'
4
4
 
5
5
  debug_enabled = ENV['DEBUG'].present? && ENV['DEBUG'].to_s == 'true'
6
+ use_redis = ENV['USE_REDIS'].present? && ENV['USE_REDIS'].to_s == 'true'
7
+ log_file_path = File.join(File.expand_path(File.dirname(__FILE__)), 'log', 'celluloid_pubsub.log')
6
8
 
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
9
 
22
10
  # actor that subscribes to a channel
23
11
  class Subscriber
24
12
  include Celluloid
25
13
  include Celluloid::Logger
26
- finalizer :shutdown
27
14
 
28
15
  def initialize(options = {})
29
16
  @client = CelluloidPubsub::Client.new({ actor: Actor.current, channel: 'test_channel' }.merge(options))
@@ -35,7 +22,6 @@ class Subscriber
35
22
  @client.publish('test_channel2', 'data' => ' subscriber got successfull subscription') # the message needs to be a Hash
36
23
  else
37
24
  puts "subscriber got message #{message.inspect}"
38
- @client.unsubscribe('test_channel')
39
25
  end
40
26
  end
41
27
 
@@ -43,48 +29,43 @@ class Subscriber
43
29
  puts "websocket connection closed: #{code.inspect}, #{reason.inspect}"
44
30
  terminate
45
31
  end
46
- def shutdown
47
- debug "#{self.class} tries to 'shudown'"
48
- terminate
49
- end
32
+
33
+
50
34
  end
51
35
 
52
36
  # actor that publishes a message in a channel
53
37
  class Publisher
54
38
  include Celluloid
55
39
  include Celluloid::Logger
56
- finalizer :shutdown
57
40
 
58
41
  def initialize(options = {})
59
42
  @client = CelluloidPubsub::Client.new({ actor: Actor.current, channel: 'test_channel2' }.merge(options))
60
43
  end
61
44
 
62
45
  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')
46
+ if @client.succesfull_subscription?(message)
47
+ puts "publisher got successful subscription #{message.inspect}"
48
+ @client.publish('test_channel', 'data' => ' my_message') # the message needs to be a Hash
49
+ else
50
+ puts "publisher got message #{message.inspect}"
51
+ end
66
52
  end
67
53
 
68
54
  def on_close(code, reason)
69
55
  puts "websocket connection closed: #{code.inspect}, #{reason.inspect}"
70
56
  terminate
71
57
  end
72
- def shutdown
73
- debug "#{self.class} tries to 'shudown'"
74
- terminate
75
- end
58
+
76
59
  end
77
60
 
78
- CelluloidPubsub::WebServer.supervise_as(:web_server, enable_debug: debug_enabled, use_redis: $use_redis)
61
+
62
+ CelluloidPubsub::WebServer.supervise_as(:web_server, enable_debug: debug_enabled, use_redis: use_redis,log_file_path: log_file_path )
79
63
  Subscriber.supervise_as(:subscriber, enable_debug: debug_enabled)
80
64
  Publisher.supervise_as(:publisher, enable_debug: debug_enabled)
81
65
  signal_received = false
82
66
 
83
- at_exit do
84
- Celluloid.shutdown
85
- end
86
67
  Signal.trap('INT') do
87
- puts "\nAn interrupt signal is happening!"
68
+ puts "\nAn interrupt signal has been triggered!"
88
69
  signal_received = true
89
70
  end
90
71
 
@@ -1,2 +1,2 @@
1
- $use_redis = false
1
+ ENV['USE_REDIS'] = 'false'
2
2
  require_relative './shared_classes'
@@ -1,3 +1,4 @@
1
+ require_relative './helper'
1
2
  module CelluloidPubsub
2
3
  # worker that subscribes to a channel or publishes to a channel
3
4
  # if it used to subscribe to a channel the worker will dispatch the messages to the actor that made the
@@ -9,8 +10,8 @@ module CelluloidPubsub
9
10
  # @!attribute connect_blk
10
11
  # @return [Proc] Block that will execute after the connection is opened
11
12
  #
12
- # @!attribute client
13
- # @return [Celluloid::WebSocket::Client] A websocket client that is used to chat witht the webserver
13
+ # @!attribute connection
14
+ # @return [Celluloid::WebSocket::Client] A websocket connection that is used to chat witht the webserver
14
15
  #
15
16
  # @!attribute options
16
17
  # @return [Hash] the options that can be used to connect to webser and send additional data
@@ -26,7 +27,9 @@ module CelluloidPubsub
26
27
  class Client
27
28
  include Celluloid
28
29
  include Celluloid::Logger
29
- attr_accessor :actor, :client, :options, :hostname, :port, :path, :channel
30
+ include CelluloidPubsub::Helper
31
+
32
+ attr_reader :actor, :connection, :options, :hostname, :port, :path, :channel
30
33
  finalizer :shutdown
31
34
  # receives a list of options that are used to connect to the webserver and an actor to which the callbacks are delegated to
32
35
  # when receiving messages from a channel
@@ -43,44 +46,61 @@ module CelluloidPubsub
43
46
  #
44
47
  # @api public
45
48
  def initialize(options)
46
- parse_options(options)
49
+ @options = options.stringify_keys!
50
+ @actor ||= @options.fetch('actor', nil)
51
+ @channel ||= @options.fetch('channel', nil)
47
52
  raise "#{self}: Please provide an actor in the options list!!!" if @actor.blank?
48
53
  raise "#{self}: Please provide an channel in the options list!!!" if @channel.blank?
49
- @actor.link Actor.current if @actor.respond_to?(:link)
50
- @client = Celluloid::WebSocket::Client.new("ws://#{@hostname}:#{@port}#{@path}", Actor.current)
51
- Actor.current.link @client
54
+ supervise_actors
55
+ setup_celluloid_logger
52
56
  end
53
57
 
54
- # the method will terminate the current actor
55
- #
58
+ def log_file_path
59
+ @log_file_path ||= @options.fetch('log_file_path', nil)
60
+ end
61
+
62
+ # the method will link the current actor to the actor that is attached to, and the connection to the current actor
56
63
  #
57
64
  # @return [void]
58
65
  #
59
66
  # @api public
60
- def shutdown
61
- debug "#{self.class} tries to 'shudown'" if debug_enabled?
62
- terminate
67
+ def supervise_actors
68
+ current_actor = Actor.current
69
+ @actor.link current_actor if @actor.respond_to?(:link)
70
+ current_actor.link connection
63
71
  end
64
72
 
65
- # check the options list for values and sets default values if not found
73
+ # the method will return the client that is used to
74
+ #
75
+ #
76
+ # @return [Celluloid::WebSocket::Client] the websocket connection used to connect to server
77
+ #
78
+ # @api public
79
+ def connection
80
+ @connection ||= Celluloid::WebSocket::Client.new("ws://#{hostname}:#{port}#{path}", Actor.current)
81
+ end
82
+
83
+ def hostname
84
+ @hostname ||= @options.fetch('hostname', CelluloidPubsub::WebServer::HOST)
85
+ end
86
+
87
+ def port
88
+ @port ||= @options.fetch('port', CelluloidPubsub::WebServer::PORT)
89
+ end
90
+
91
+ def path
92
+ @path ||= @options.fetch('path', CelluloidPubsub::WebServer::PATH)
93
+ end
94
+
95
+ # the method will terminate the current actor
66
96
  #
67
- # @param [Hash] options the options that can be used to connect to webser and send additional data
68
- # @option options [String] :actor The actor that made the connection
69
- # @option options [String]:hostname The hostname on which the webserver runs on
70
- # @option options [String] :port The port on which the webserver runs on
71
- # @option options [String] :path The request path that the webserver accepts
72
97
  #
73
98
  # @return [void]
74
99
  #
75
100
  # @api public
76
- def parse_options(options)
77
- raise 'Options is not a hash' unless options.is_a?(Hash)
78
- @options = options.stringify_keys!
79
- @actor = @options.fetch('actor', nil)
80
- @channel = @options.fetch('channel', nil)
81
- @hostname = @options.fetch('hostname', CelluloidPubsub::WebServer::HOST)
82
- @port = @options.fetch('port', CelluloidPubsub::WebServer::PORT)
83
- @path = @options.fetch('path', CelluloidPubsub::WebServer::PATH)
101
+ def shutdown
102
+ log_debug "#{self.class} tries to 'shudown'"
103
+ terminate
84
104
  end
85
105
 
86
106
  # checks if debug is enabled
@@ -101,21 +121,10 @@ module CelluloidPubsub
101
121
  #
102
122
  # @api public
103
123
  def subscribe(channel)
104
- debug("#{@actor.class} tries to subscribe to channel #{channel}") if debug_enabled?
124
+ log_debug("#{@actor.class} tries to subscribe to channel #{channel}")
105
125
  async.send_action('subscribe', channel)
106
126
  end
107
127
 
108
- # checks if the message has the successfull subscription action
109
- #
110
- # @param [string] message
111
- #
112
- # @return [void]
113
- #
114
- # @api public
115
- def succesfull_subscription?(message)
116
- message.present? && message['client_action'].present? && message['client_action'] == 'successful_subscription'
117
- end
118
-
119
128
  # publishes to a channel some data (can be anything)
120
129
  #
121
130
  # @param [string] channel
@@ -165,10 +174,14 @@ module CelluloidPubsub
165
174
  #
166
175
  # @api public
167
176
  def on_open
168
- debug("#{@actor.class} websocket connection opened") if debug_enabled?
177
+ log_debug("#{@actor.class} websocket connection opened")
169
178
  async.subscribe(@channel)
170
179
  end
171
180
 
181
+ def log_debug(message)
182
+ debug message if debug_enabled?
183
+ end
184
+
172
185
  # callback executes when actor receives a message from a subscribed channel
173
186
  # and parses the message using JSON.parse and dispatches the parsed
174
187
  # message to the original actor that made the connection
@@ -179,9 +192,8 @@ module CelluloidPubsub
179
192
  #
180
193
  # @api public
181
194
  def on_message(data)
182
- debug("#{@actor.class} received plain #{data}") if debug_enabled?
183
195
  message = JSON.parse(data)
184
- debug("#{@actor.class} received JSON #{message}") if debug_enabled?
196
+ log_debug("#{@actor.class} received JSON #{message}")
185
197
  @actor.async.on_message(message)
186
198
  end
187
199
 
@@ -195,9 +207,9 @@ module CelluloidPubsub
195
207
  #
196
208
  # @api public
197
209
  def on_close(code, reason)
198
- @client.terminate
210
+ connection.terminate
199
211
  terminate
200
- debug("#{@actor.class} dispatching on close #{code} #{reason}") if debug_enabled?
212
+ log_debug("#{@actor.class} dispatching on close #{code} #{reason}")
201
213
  @actor.async.on_close(code, reason)
202
214
  end
203
215
 
@@ -213,9 +225,8 @@ module CelluloidPubsub
213
225
  #
214
226
  # @api private
215
227
  def send_action(action, channel = nil, data = {})
216
- publishing_data = { 'client_action' => action }
217
- publishing_data = publishing_data.merge('channel' => channel) if channel.present?
218
- publishing_data = publishing_data.merge('data' => data) if data.present?
228
+ data = data.is_a?(Hash) ? data : {}
229
+ publishing_data = { 'client_action' => action, 'channel' => channel, 'data' => data }.reject { |_key, value| value.blank? }
219
230
  async.chat(publishing_data)
220
231
  end
221
232
 
@@ -232,12 +243,11 @@ module CelluloidPubsub
232
243
  final_message = nil
233
244
  if message.is_a?(Hash)
234
245
  final_message = message.to_json
235
- debug("#{@actor.class} sends #{message.to_json}") if debug_enabled?
236
246
  else
237
247
  final_message = JSON.dump(action: 'message', message: message)
238
- debug("#{@actor.class} sends JSON #{final_message}") if debug_enabled?
239
248
  end
240
- @client.text final_message
249
+ log_debug("#{@actor.class} sends JSON #{final_message}")
250
+ connection.text final_message
241
251
  end
242
252
  end
243
253
  end
@@ -0,0 +1,64 @@
1
+ module CelluloidPubsub
2
+ # class that holds the options that are configurable for this gem
3
+ module Helper
4
+ # checks if the message has the successfull subscription action
5
+ #
6
+ # @param [string] message
7
+ #
8
+ # @return [void]
9
+ #
10
+ # @api public
11
+ def succesfull_subscription?(message)
12
+ message.is_a?(Hash) && message['client_action'] == 'successful_subscription'
13
+ end
14
+
15
+ module_function
16
+
17
+ def setup_celluloid_logger
18
+ return if !debug_enabled? || (respond_to?(:log_file_path) && log_file_path.blank?)
19
+ setup_log_file
20
+ Celluloid.logger = ::Logger.new(log_file_path.present? ? log_file_path : STDOUT)
21
+ setup_celluloid_exception_handler
22
+ end
23
+
24
+ def setup_celluloid_exception_handler
25
+ Celluloid.task_class = Celluloid::TaskThread
26
+ Celluloid.exception_handler do |ex|
27
+ puts ex unless filtered_error?(ex)
28
+ end
29
+ end
30
+
31
+ def setup_log_file
32
+ return if !debug_enabled? || (respond_to?(:log_file_path) && log_file_path.blank?)
33
+ FileUtils.mkdir_p(File.dirname(log_file_path)) unless File.directory?(log_file_path)
34
+ log_file = File.open(log_file_path, 'w')
35
+ log_file.sync = true
36
+ end
37
+
38
+ def filtered_error?(error)
39
+ [Interrupt].any? { |class_name| error.is_a?(class_name) }
40
+ end
41
+
42
+ # receives a list of options that are used to configure the webserver
43
+ #
44
+ # @param [Hash] options the options that can be used to connect to webser and send additional data
45
+ # @option options [String]:hostname The hostname on which the webserver runs on
46
+ # @option options [Integer] :port The port on which the webserver runs on
47
+ # @option options [String] :path The request path that the webserver accepts
48
+ # @option options [Boolean] :spy Enable this only if you want to enable debugging for the webserver
49
+ # @option options [Integer]:backlog How many connections the server accepts
50
+ #
51
+ # @return [void]
52
+ #
53
+ # @api public
54
+ def parse_options(options)
55
+ options = options.is_a?(Array) ? options.first : options
56
+ options = options.is_a?(Hash) ? options.stringify_keys : {}
57
+ options
58
+ end
59
+
60
+ def log_debug(message)
61
+ debug message if respond_to?(:debug_enabled?) && debug_enabled?
62
+ end
63
+ end
64
+ end