wamp-worker 0.1.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.
Files changed (129) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +204 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/bin/wamp-worker +46 -0
  13. data/lib/wamp/worker.rb +132 -0
  14. data/lib/wamp/worker/config.rb +184 -0
  15. data/lib/wamp/worker/handler.rb +196 -0
  16. data/lib/wamp/worker/proxy/backgrounder.rb +38 -0
  17. data/lib/wamp/worker/proxy/base.rb +101 -0
  18. data/lib/wamp/worker/proxy/dispatcher.rb +115 -0
  19. data/lib/wamp/worker/proxy/requestor.rb +91 -0
  20. data/lib/wamp/worker/queue.rb +135 -0
  21. data/lib/wamp/worker/rails.rb +28 -0
  22. data/lib/wamp/worker/runner.rb +240 -0
  23. data/lib/wamp/worker/ticker.rb +30 -0
  24. data/lib/wamp/worker/version.rb +5 -0
  25. data/spec/spec_helper.rb +29 -0
  26. data/spec/support/client_stub.rb +47 -0
  27. data/spec/support/handler_stub.rb +105 -0
  28. data/spec/support/redis_stub.rb +89 -0
  29. data/spec/support/session_stub.rb +101 -0
  30. data/spec/wamp/worker/config_spec.rb +90 -0
  31. data/spec/wamp/worker/handler_spec.rb +162 -0
  32. data/spec/wamp/worker/proxy_spec.rb +153 -0
  33. data/spec/wamp/worker/queue_spec.rb +49 -0
  34. data/spec/wamp/worker/runner_spec.rb +108 -0
  35. data/spec/wamp/worker_spec.rb +8 -0
  36. data/test/app_test.rb +124 -0
  37. data/test/hello.py +50 -0
  38. data/test/sidekiq.yml +5 -0
  39. data/test/wamp_test/.generators +8 -0
  40. data/test/wamp_test/.ruby-version +1 -0
  41. data/test/wamp_test/Gemfile +65 -0
  42. data/test/wamp_test/Gemfile.lock +246 -0
  43. data/test/wamp_test/README.md +24 -0
  44. data/test/wamp_test/Rakefile +6 -0
  45. data/test/wamp_test/app/assets/config/manifest.js +3 -0
  46. data/test/wamp_test/app/assets/images/.keep +0 -0
  47. data/test/wamp_test/app/assets/javascripts/application.js +16 -0
  48. data/test/wamp_test/app/assets/javascripts/cable.js +13 -0
  49. data/test/wamp_test/app/assets/javascripts/channels/.keep +0 -0
  50. data/test/wamp_test/app/assets/stylesheets/application.css +15 -0
  51. data/test/wamp_test/app/channels/application_cable/channel.rb +4 -0
  52. data/test/wamp_test/app/channels/application_cable/connection.rb +4 -0
  53. data/test/wamp_test/app/controllers/add_controller.rb +11 -0
  54. data/test/wamp_test/app/controllers/application_controller.rb +3 -0
  55. data/test/wamp_test/app/controllers/concerns/.keep +0 -0
  56. data/test/wamp_test/app/controllers/ping_controller.rb +7 -0
  57. data/test/wamp_test/app/handlers/add_handler.rb +9 -0
  58. data/test/wamp_test/app/handlers/back_add_handler.rb +26 -0
  59. data/test/wamp_test/app/handlers/back_ping_handler.rb +10 -0
  60. data/test/wamp_test/app/handlers/ping_handler.rb +10 -0
  61. data/test/wamp_test/app/helpers/application_helper.rb +2 -0
  62. data/test/wamp_test/app/jobs/application_job.rb +2 -0
  63. data/test/wamp_test/app/mailers/application_mailer.rb +4 -0
  64. data/test/wamp_test/app/models/application_record.rb +3 -0
  65. data/test/wamp_test/app/models/concerns/.keep +0 -0
  66. data/test/wamp_test/app/views/layouts/application.html.erb +15 -0
  67. data/test/wamp_test/app/views/layouts/mailer.html.erb +13 -0
  68. data/test/wamp_test/app/views/layouts/mailer.text.erb +1 -0
  69. data/test/wamp_test/bin/bundle +3 -0
  70. data/test/wamp_test/bin/rails +9 -0
  71. data/test/wamp_test/bin/rake +9 -0
  72. data/test/wamp_test/bin/setup +36 -0
  73. data/test/wamp_test/bin/spring +17 -0
  74. data/test/wamp_test/bin/update +31 -0
  75. data/test/wamp_test/bin/yarn +11 -0
  76. data/test/wamp_test/config.ru +5 -0
  77. data/test/wamp_test/config/application.rb +19 -0
  78. data/test/wamp_test/config/boot.rb +4 -0
  79. data/test/wamp_test/config/cable.yml +10 -0
  80. data/test/wamp_test/config/credentials.yml.enc +1 -0
  81. data/test/wamp_test/config/database.yml +25 -0
  82. data/test/wamp_test/config/environment.rb +5 -0
  83. data/test/wamp_test/config/environments/development.rb +61 -0
  84. data/test/wamp_test/config/environments/production.rb +94 -0
  85. data/test/wamp_test/config/environments/test.rb +46 -0
  86. data/test/wamp_test/config/initializers/application_controller_renderer.rb +8 -0
  87. data/test/wamp_test/config/initializers/assets.rb +14 -0
  88. data/test/wamp_test/config/initializers/backtrace_silencers.rb +7 -0
  89. data/test/wamp_test/config/initializers/content_security_policy.rb +25 -0
  90. data/test/wamp_test/config/initializers/cookies_serializer.rb +5 -0
  91. data/test/wamp_test/config/initializers/filter_parameter_logging.rb +4 -0
  92. data/test/wamp_test/config/initializers/inflections.rb +16 -0
  93. data/test/wamp_test/config/initializers/mime_types.rb +4 -0
  94. data/test/wamp_test/config/initializers/wamp-worker.rb +8 -0
  95. data/test/wamp_test/config/initializers/wrap_parameters.rb +14 -0
  96. data/test/wamp_test/config/locales/en.yml +33 -0
  97. data/test/wamp_test/config/master.key +1 -0
  98. data/test/wamp_test/config/puma.rb +34 -0
  99. data/test/wamp_test/config/routes.rb +4 -0
  100. data/test/wamp_test/config/sidekiq.yml +6 -0
  101. data/test/wamp_test/config/spring.rb +6 -0
  102. data/test/wamp_test/config/storage.yml +34 -0
  103. data/test/wamp_test/db/development.sqlite3 +0 -0
  104. data/test/wamp_test/db/seeds.rb +7 -0
  105. data/test/wamp_test/lib/assets/.keep +0 -0
  106. data/test/wamp_test/lib/tasks/.keep +0 -0
  107. data/test/wamp_test/package.json +5 -0
  108. data/test/wamp_test/public/404.html +67 -0
  109. data/test/wamp_test/public/422.html +67 -0
  110. data/test/wamp_test/public/500.html +66 -0
  111. data/test/wamp_test/public/apple-touch-icon-precomposed.png +0 -0
  112. data/test/wamp_test/public/apple-touch-icon.png +0 -0
  113. data/test/wamp_test/public/favicon.ico +0 -0
  114. data/test/wamp_test/public/robots.txt +1 -0
  115. data/test/wamp_test/storage/.keep +0 -0
  116. data/test/wamp_test/test/application_system_test_case.rb +5 -0
  117. data/test/wamp_test/test/controllers/.keep +0 -0
  118. data/test/wamp_test/test/fixtures/.keep +0 -0
  119. data/test/wamp_test/test/fixtures/files/.keep +0 -0
  120. data/test/wamp_test/test/helpers/.keep +0 -0
  121. data/test/wamp_test/test/integration/.keep +0 -0
  122. data/test/wamp_test/test/mailers/.keep +0 -0
  123. data/test/wamp_test/test/models/.keep +0 -0
  124. data/test/wamp_test/test/system/.keep +0 -0
  125. data/test/wamp_test/test/test_helper.rb +10 -0
  126. data/test/wamp_test/vendor/.keep +0 -0
  127. data/test/web/index.html +101 -0
  128. data/wamp-worker.gemspec +32 -0
  129. metadata +395 -0
@@ -0,0 +1,30 @@
1
+ module Wamp
2
+ module Worker
3
+
4
+ class Ticker
5
+ attr_reader :redis, :ticker_key
6
+
7
+ # Constructor
8
+ #
9
+ # @param name [Symbol] - The name of the worker
10
+ def initialize(name)
11
+ @redis = Wamp::Worker.config.redis(name)
12
+ @ticker_key = "wamp:#{name}:tick"
13
+ end
14
+
15
+ # Returns the tick for the worker
16
+ #
17
+ # @return [Int] - The value of the tick
18
+ def get
19
+ self.redis.get(self.ticker_key) || 0
20
+ end
21
+
22
+ # Increments the tick
23
+ #
24
+ def increment
25
+ self.redis.incr(self.ticker_key)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module Wamp
2
+ module Worker
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter 'spec/'
4
+ end
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
7
+ require "wamp/worker"
8
+
9
+ Dir[File.expand_path('spec/support/**/*.rb')].each { |f| require f }
10
+
11
+ require 'sidekiq/testing'
12
+ Sidekiq::Testing.inline!
13
+
14
+ Wamp::Worker.log_level = :error
15
+
16
+ RSpec.configure do |config|
17
+ config.before(:each) {
18
+ stub_redis
19
+ stub_client
20
+ }
21
+ end
22
+
23
+ def stub_redis
24
+ allow(::Redis).to receive(:new).and_return(RedisStub.new)
25
+ end
26
+
27
+ def stub_client
28
+ allow(::Wamp::Client::Connection).to receive(:new).and_return(ClientStub.new({}))
29
+ end
@@ -0,0 +1,47 @@
1
+ class ClientStub
2
+ attr_accessor :session, :options, :is_open
3
+
4
+ def transport_class
5
+ Wamp::Client::Transport::EventMachineBase
6
+ end
7
+
8
+ def initialize(options)
9
+ self.options = options
10
+ self.is_open = false
11
+ self.session = SessionStub.new
12
+ @callbacks = {}
13
+ end
14
+
15
+ def open
16
+ self.is_open = true
17
+
18
+ # Fake connect
19
+ trigger(:connect) { |handler| handler.call }
20
+
21
+ # Fake challenge
22
+ trigger(:challenge) { |handler| handler.call('wampcra', {}) } if self.options[:should_challenge]
23
+
24
+ # Fake join
25
+ trigger(:join) { |handler| handler.call(self.session, {}) }
26
+ end
27
+
28
+ def close
29
+ # Fake leave
30
+ trigger(:leave) { |handler| handler.call('left', {}) }
31
+
32
+ # Fake disconnect
33
+ trigger(:disconnect) { |handler| handler.call('left') }
34
+
35
+ self.is_open = false
36
+ end
37
+
38
+ def on(event, &callback)
39
+ @callbacks[event] = callback
40
+ end
41
+
42
+ def trigger(event, &callback)
43
+ handler = @callbacks[event]
44
+ callback.call(handler) if handler
45
+ end
46
+
47
+ end
@@ -0,0 +1,105 @@
1
+ class Handler
2
+
3
+ def topic
4
+ self.class.increment_run_count
5
+ end
6
+
7
+ def return_error
8
+ self.class.increment_run_count
9
+ Wamp::Client::Response::CallError.new("error")
10
+ end
11
+
12
+ def throw_error
13
+ self.class.increment_run_count
14
+ raise Wamp::Client::Response::CallError.new("error")
15
+ end
16
+
17
+ def throw_exception
18
+ self.class.increment_run_count
19
+ raise StandardError.new("error")
20
+ end
21
+
22
+ def call_result
23
+ self.class.increment_run_count
24
+ Wamp::Client::Response::CallResult.new([(self.args[0] + 2)])
25
+ end
26
+
27
+ def normal_result
28
+ self.class.increment_run_count
29
+ self.args[0] + 3
30
+ end
31
+
32
+ def nil_result
33
+ self.class.increment_run_count
34
+ nil
35
+ end
36
+
37
+ def proxy_result
38
+ self.class.increment_run_count
39
+ response = nil
40
+ self.session.call("normal_result", self.args, self.kwargs) do |result, error, details|
41
+ response = result[:args][0]
42
+ end
43
+ response
44
+ end
45
+
46
+ def progress_result
47
+ self.class.increment_run_count
48
+ self.progress(0)
49
+ self.progress(0.5)
50
+ self.progress(1.0)
51
+ self.args[0] + 4
52
+ end
53
+
54
+ end
55
+
56
+
57
+ class NormalHandler < Handler
58
+ include Wamp::Worker::Handler
59
+
60
+ @@run_count = 0
61
+ def self.increment_run_count
62
+ @@run_count += 1
63
+ end
64
+ def self.run_count
65
+ @@run_count
66
+ end
67
+
68
+ subscribe "topic", :topic
69
+ subscribe "other.topic", :topic, :name => :other
70
+ register "return_error", :return_error
71
+ register "throw_error", :throw_error
72
+ register "throw_exception", :throw_exception
73
+ register "call_result", :call_result
74
+ register "other.call_result", :call_result, :name => :other
75
+ register "normal_result", :normal_result
76
+ register "nil_result", :nil_result
77
+ register "proxy_result", :proxy_result
78
+ register "progress_result", :progress_result
79
+ end
80
+
81
+ class BackgroundHandler < Handler
82
+ include Wamp::Worker::BackgroundHandler
83
+
84
+ @@run_count = 0
85
+ def self.increment_run_count
86
+ @@run_count += 1
87
+ end
88
+ def self.run_count
89
+ @@run_count
90
+ end
91
+
92
+ subscribe "back.topic", :topic
93
+ subscribe "back.other.topic", :topic, :name => :other
94
+ register "back.return_error", :return_error
95
+ register "back.throw_error", :throw_error
96
+ register "back.throw_exception", :throw_exception
97
+ register "back.call_result", :call_result
98
+ register "back.other.call_result", :call_result, :name => :other
99
+ register "back.normal_result", :normal_result
100
+ register "back.nil_result", :nil_result
101
+ register "back.proxy_result", :proxy_result
102
+ register "back.progress_result", :progress_result
103
+ end
104
+
105
+
@@ -0,0 +1,89 @@
1
+ require 'thread'
2
+
3
+ class RedisStub
4
+ attr_reader :data, :semaphore
5
+
6
+ def initialize
7
+ @data = {}
8
+ @semaphore = Mutex.new
9
+ end
10
+
11
+ def lpush(key, data)
12
+ self.semaphore.synchronize {
13
+ list = self.data[key] || []
14
+ list.unshift data
15
+ self.data[key] = list
16
+ }
17
+ end
18
+
19
+ def exists(key)
20
+ self.semaphore.synchronize {
21
+ self.data[key] != nil
22
+ }
23
+ end
24
+
25
+ def get(key)
26
+ self.semaphore.synchronize {
27
+ self.data[key]
28
+ }
29
+ end
30
+
31
+ def set(key, value, options={})
32
+ self.semaphore.synchronize {
33
+ self.data[key] = value
34
+ }
35
+ end
36
+
37
+ def del(key)
38
+ self.semaphore.synchronize {
39
+ self.data.delete(key)
40
+ 1
41
+ }
42
+ end
43
+
44
+ def rpop(key)
45
+ self.semaphore.synchronize {
46
+ (self.data[key] || []).pop
47
+ }
48
+ end
49
+
50
+ def brpop(key, **args)
51
+ value = nil
52
+ timeout = false
53
+ start_time = Time.new.to_i
54
+
55
+ # BRPOP also supports an array of keys
56
+ keys = key.is_a?(Array) ? key : [key]
57
+ matched_key = nil
58
+
59
+ while value == nil and not timeout
60
+ self.semaphore.synchronize {
61
+ keys.each do |temp_key|
62
+ value = (self.data[temp_key] || []).pop
63
+ if value != nil
64
+ matched_key = temp_key
65
+ break
66
+ end
67
+ end
68
+ }
69
+
70
+ if args[:timeout] != nil
71
+ current_time = Time.new.to_i
72
+ if current_time > args[:timeout]+start_time
73
+ timeout = true
74
+ end
75
+ end
76
+ end
77
+
78
+ value != nil ? [matched_key, value] : nil
79
+ end
80
+
81
+ def incr(key)
82
+ self.semaphore.synchronize {
83
+ value = self.data[key] || 0
84
+ value += 1
85
+ self.data[key] = value
86
+ }
87
+ end
88
+
89
+ end
@@ -0,0 +1,101 @@
1
+ class SessionStub
2
+ attr_reader :subscriptions, :registrations, :defers, :calls
3
+
4
+ def initialize
5
+ @subscriptions = {}
6
+ @registrations = {}
7
+ @defers = {}
8
+ @calls = {}
9
+ end
10
+
11
+ def publish(topic, args=nil, kwargs=nil, options={}, &callback)
12
+ subscription = self.subscriptions[topic]
13
+ error = nil
14
+
15
+ if subscription
16
+ subscription.call(args, kwargs, {})
17
+ else
18
+ error = Wamp::Client::Response::CallError.new("wamp.no_subscriber").to_hash
19
+ end
20
+
21
+ if callback and options[:acknowledge]
22
+ callback.call(1234, error, { topic: topic })
23
+ end
24
+ end
25
+
26
+ def call(procedure, args=nil, kwargs=nil, options={}, &callback)
27
+ registration = self.registrations[procedure]
28
+ request = SecureRandom.uuid
29
+
30
+ self.calls[request] = callback
31
+
32
+ if registration
33
+ details = options.clone
34
+ details[:request] = request
35
+
36
+ result = Wamp::Client::Response.invoke_handler do
37
+ registration.call(args, kwargs, details)
38
+ end
39
+ else
40
+ result = Wamp::Client::Response::CallError.new("wamp.no_procedure")
41
+ end
42
+
43
+ if callback
44
+ if result.is_a?(Wamp::Client::Response::CallDefer)
45
+ self.defers[request] = callback
46
+ else
47
+ self.yield(request, result, options)
48
+ end
49
+ end
50
+
51
+ self.calls.delete(request)
52
+ end
53
+
54
+ def register(procedure, handler, options=nil, interrupt=nil, &callback)
55
+ self.registrations[procedure] = handler
56
+
57
+ if callback
58
+ callback.call({procedure: procedure, handler: handler}, nil, nil)
59
+ end
60
+ end
61
+
62
+ def subscribe(topic, handler, options={}, &callback)
63
+ self.subscriptions[topic] = handler
64
+
65
+ if callback
66
+ callback.call({topic: topic, handler: handler}, nil, nil)
67
+ end
68
+ end
69
+
70
+ def yield(request, result, options={}, check_defer=false)
71
+
72
+ # Get the callback
73
+ callback =
74
+ if check_defer
75
+ callback = self.defers[request]
76
+ self.defers.delete(request) unless options[:progress]
77
+ callback
78
+ else
79
+ self.calls[request]
80
+ end
81
+
82
+ # If there is a callback, handle it
83
+ if callback
84
+
85
+ # Create the response object
86
+ result = Wamp::Client::Response::CallResult.ensure(result, allow_error: true)
87
+
88
+ # Create the details
89
+ details = { request: request, progress: options[:progress] }
90
+
91
+ # Call the callback
92
+ if result.is_a?(Wamp::Client::Response::CallError)
93
+ callback.call(nil, result.to_hash, details)
94
+ else
95
+ callback.call(result.to_hash, nil, details)
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,90 @@
1
+ require "spec_helper"
2
+
3
+ class Handler1
4
+ include Wamp::Worker::Handler
5
+
6
+ def handler
7
+ end
8
+ end
9
+
10
+ describe Wamp::Worker::Config do
11
+ let(:config) { described_class.new }
12
+ let(:proxy) { Wamp::Worker::ConfigProxy.new(config) }
13
+ let(:other_proxy) { Wamp::Worker::ConfigProxy.new(config, :other) }
14
+
15
+ it "sets everything to the default" do
16
+ proxy.configure do
17
+ timeout 100
18
+ connection option: true
19
+
20
+ subscribe "topic", Handler1, :handler, match: true
21
+ register "procedure", Handler1, :handler
22
+ end
23
+
24
+ expect(config.connection).to eq({option: true})
25
+ expect(config.timeout).to eq(100)
26
+ expect(config.redis.is_a?(RedisStub)).to eq(true)
27
+ expect(config.registrations.count).to eq(1)
28
+ expect(config.subscriptions.count).to eq(1)
29
+
30
+ expect(config.connection(:default)).to eq({option: true})
31
+ expect(config.timeout(:default)).to eq(100)
32
+ expect(config.redis(:default).is_a?(RedisStub)).to eq(true)
33
+ expect(config.registrations(:default).count).to eq(1)
34
+ expect(config.subscriptions(:default).count).to eq(1)
35
+ end
36
+
37
+ it "sets everything to other" do
38
+ other_proxy.configure do
39
+ timeout 100
40
+ connection option: true
41
+
42
+ subscribe "topic", Handler1, :handler, match: true
43
+ register "procedure", Handler1, :handler
44
+ end
45
+
46
+ # Defaults
47
+ expect(config.connection).to eq({})
48
+ expect(config.timeout).to eq(60)
49
+ expect(config.redis.is_a?(RedisStub)).to eq(true)
50
+ expect(config.registrations.count).to eq(0)
51
+ expect(config.subscriptions.count).to eq(0)
52
+
53
+ expect(config.connection(:other)).to eq({option: true})
54
+ expect(config.timeout(:other)).to eq(100)
55
+ expect(config.redis(:other).is_a?(RedisStub)).to eq(true)
56
+ expect(config.registrations(:other).count).to eq(1)
57
+ expect(config.subscriptions(:other).count).to eq(1)
58
+ end
59
+
60
+ it "does both" do
61
+ proxy.configure do
62
+ timeout 100
63
+ connection option: true
64
+
65
+ subscribe "topic", Handler1, :handler, match: true
66
+ register "procedure", Handler1, :handler
67
+ end
68
+
69
+ other_proxy.configure do
70
+ timeout 110
71
+ connection option: false
72
+
73
+ subscribe "topic", Handler1, :handler, match: true
74
+ register "procedure", Handler1, :handler
75
+ end
76
+
77
+ expect(config.connection).to eq({option: true})
78
+ expect(config.timeout).to eq(100)
79
+ expect(config.redis.is_a?(RedisStub)).to eq(true)
80
+ expect(config.registrations.count).to eq(1)
81
+ expect(config.subscriptions.count).to eq(1)
82
+
83
+ expect(config.connection(:other)).to eq({option: false})
84
+ expect(config.timeout(:other)).to eq(110)
85
+ expect(config.redis(:other).is_a?(RedisStub)).to eq(true)
86
+ expect(config.registrations(:other).count).to eq(1)
87
+ expect(config.subscriptions(:other).count).to eq(1)
88
+ end
89
+ end
90
+