wamp-worker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+