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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +204 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/wamp-worker +46 -0
- data/lib/wamp/worker.rb +132 -0
- data/lib/wamp/worker/config.rb +184 -0
- data/lib/wamp/worker/handler.rb +196 -0
- data/lib/wamp/worker/proxy/backgrounder.rb +38 -0
- data/lib/wamp/worker/proxy/base.rb +101 -0
- data/lib/wamp/worker/proxy/dispatcher.rb +115 -0
- data/lib/wamp/worker/proxy/requestor.rb +91 -0
- data/lib/wamp/worker/queue.rb +135 -0
- data/lib/wamp/worker/rails.rb +28 -0
- data/lib/wamp/worker/runner.rb +240 -0
- data/lib/wamp/worker/ticker.rb +30 -0
- data/lib/wamp/worker/version.rb +5 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/client_stub.rb +47 -0
- data/spec/support/handler_stub.rb +105 -0
- data/spec/support/redis_stub.rb +89 -0
- data/spec/support/session_stub.rb +101 -0
- data/spec/wamp/worker/config_spec.rb +90 -0
- data/spec/wamp/worker/handler_spec.rb +162 -0
- data/spec/wamp/worker/proxy_spec.rb +153 -0
- data/spec/wamp/worker/queue_spec.rb +49 -0
- data/spec/wamp/worker/runner_spec.rb +108 -0
- data/spec/wamp/worker_spec.rb +8 -0
- data/test/app_test.rb +124 -0
- data/test/hello.py +50 -0
- data/test/sidekiq.yml +5 -0
- data/test/wamp_test/.generators +8 -0
- data/test/wamp_test/.ruby-version +1 -0
- data/test/wamp_test/Gemfile +65 -0
- data/test/wamp_test/Gemfile.lock +246 -0
- data/test/wamp_test/README.md +24 -0
- data/test/wamp_test/Rakefile +6 -0
- data/test/wamp_test/app/assets/config/manifest.js +3 -0
- data/test/wamp_test/app/assets/images/.keep +0 -0
- data/test/wamp_test/app/assets/javascripts/application.js +16 -0
- data/test/wamp_test/app/assets/javascripts/cable.js +13 -0
- data/test/wamp_test/app/assets/javascripts/channels/.keep +0 -0
- data/test/wamp_test/app/assets/stylesheets/application.css +15 -0
- data/test/wamp_test/app/channels/application_cable/channel.rb +4 -0
- data/test/wamp_test/app/channels/application_cable/connection.rb +4 -0
- data/test/wamp_test/app/controllers/add_controller.rb +11 -0
- data/test/wamp_test/app/controllers/application_controller.rb +3 -0
- data/test/wamp_test/app/controllers/concerns/.keep +0 -0
- data/test/wamp_test/app/controllers/ping_controller.rb +7 -0
- data/test/wamp_test/app/handlers/add_handler.rb +9 -0
- data/test/wamp_test/app/handlers/back_add_handler.rb +26 -0
- data/test/wamp_test/app/handlers/back_ping_handler.rb +10 -0
- data/test/wamp_test/app/handlers/ping_handler.rb +10 -0
- data/test/wamp_test/app/helpers/application_helper.rb +2 -0
- data/test/wamp_test/app/jobs/application_job.rb +2 -0
- data/test/wamp_test/app/mailers/application_mailer.rb +4 -0
- data/test/wamp_test/app/models/application_record.rb +3 -0
- data/test/wamp_test/app/models/concerns/.keep +0 -0
- data/test/wamp_test/app/views/layouts/application.html.erb +15 -0
- data/test/wamp_test/app/views/layouts/mailer.html.erb +13 -0
- data/test/wamp_test/app/views/layouts/mailer.text.erb +1 -0
- data/test/wamp_test/bin/bundle +3 -0
- data/test/wamp_test/bin/rails +9 -0
- data/test/wamp_test/bin/rake +9 -0
- data/test/wamp_test/bin/setup +36 -0
- data/test/wamp_test/bin/spring +17 -0
- data/test/wamp_test/bin/update +31 -0
- data/test/wamp_test/bin/yarn +11 -0
- data/test/wamp_test/config.ru +5 -0
- data/test/wamp_test/config/application.rb +19 -0
- data/test/wamp_test/config/boot.rb +4 -0
- data/test/wamp_test/config/cable.yml +10 -0
- data/test/wamp_test/config/credentials.yml.enc +1 -0
- data/test/wamp_test/config/database.yml +25 -0
- data/test/wamp_test/config/environment.rb +5 -0
- data/test/wamp_test/config/environments/development.rb +61 -0
- data/test/wamp_test/config/environments/production.rb +94 -0
- data/test/wamp_test/config/environments/test.rb +46 -0
- data/test/wamp_test/config/initializers/application_controller_renderer.rb +8 -0
- data/test/wamp_test/config/initializers/assets.rb +14 -0
- data/test/wamp_test/config/initializers/backtrace_silencers.rb +7 -0
- data/test/wamp_test/config/initializers/content_security_policy.rb +25 -0
- data/test/wamp_test/config/initializers/cookies_serializer.rb +5 -0
- data/test/wamp_test/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/wamp_test/config/initializers/inflections.rb +16 -0
- data/test/wamp_test/config/initializers/mime_types.rb +4 -0
- data/test/wamp_test/config/initializers/wamp-worker.rb +8 -0
- data/test/wamp_test/config/initializers/wrap_parameters.rb +14 -0
- data/test/wamp_test/config/locales/en.yml +33 -0
- data/test/wamp_test/config/master.key +1 -0
- data/test/wamp_test/config/puma.rb +34 -0
- data/test/wamp_test/config/routes.rb +4 -0
- data/test/wamp_test/config/sidekiq.yml +6 -0
- data/test/wamp_test/config/spring.rb +6 -0
- data/test/wamp_test/config/storage.yml +34 -0
- data/test/wamp_test/db/development.sqlite3 +0 -0
- data/test/wamp_test/db/seeds.rb +7 -0
- data/test/wamp_test/lib/assets/.keep +0 -0
- data/test/wamp_test/lib/tasks/.keep +0 -0
- data/test/wamp_test/package.json +5 -0
- data/test/wamp_test/public/404.html +67 -0
- data/test/wamp_test/public/422.html +67 -0
- data/test/wamp_test/public/500.html +66 -0
- data/test/wamp_test/public/apple-touch-icon-precomposed.png +0 -0
- data/test/wamp_test/public/apple-touch-icon.png +0 -0
- data/test/wamp_test/public/favicon.ico +0 -0
- data/test/wamp_test/public/robots.txt +1 -0
- data/test/wamp_test/storage/.keep +0 -0
- data/test/wamp_test/test/application_system_test_case.rb +5 -0
- data/test/wamp_test/test/controllers/.keep +0 -0
- data/test/wamp_test/test/fixtures/.keep +0 -0
- data/test/wamp_test/test/fixtures/files/.keep +0 -0
- data/test/wamp_test/test/helpers/.keep +0 -0
- data/test/wamp_test/test/integration/.keep +0 -0
- data/test/wamp_test/test/mailers/.keep +0 -0
- data/test/wamp_test/test/models/.keep +0 -0
- data/test/wamp_test/test/system/.keep +0 -0
- data/test/wamp_test/test/test_helper.rb +10 -0
- data/test/wamp_test/vendor/.keep +0 -0
- data/test/web/index.html +101 -0
- data/wamp-worker.gemspec +32 -0
- metadata +395 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
|
3
|
+
module Wamp
|
4
|
+
module Worker
|
5
|
+
module Proxy
|
6
|
+
|
7
|
+
class Dispatcher < Base
|
8
|
+
attr_accessor :session
|
9
|
+
|
10
|
+
# We want to timeout every few seconds so higher level code can
|
11
|
+
# look for a shutdown
|
12
|
+
TIMEOUT = 2
|
13
|
+
|
14
|
+
# Constructor
|
15
|
+
#
|
16
|
+
def initialize(name, session=nil, uuid: nil)
|
17
|
+
super name, uuid: uuid
|
18
|
+
self.session = session
|
19
|
+
end
|
20
|
+
|
21
|
+
# Increments the ticker
|
22
|
+
#
|
23
|
+
def increment_ticker
|
24
|
+
self.ticker.increment
|
25
|
+
end
|
26
|
+
|
27
|
+
# Check the queues
|
28
|
+
#
|
29
|
+
def check_queues
|
30
|
+
check_queue [self.command_req_queue, self.background_res_queue]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Executes the request
|
34
|
+
#
|
35
|
+
# @param request [Descriptor] - The request
|
36
|
+
def process(descriptor)
|
37
|
+
return unless descriptor != nil
|
38
|
+
|
39
|
+
raise(RuntimeError, "must have a session to process a descriptor") unless self.session != nil
|
40
|
+
|
41
|
+
# Create the callback
|
42
|
+
callback = -> result, error, details {
|
43
|
+
# Need to remove the session from the details response
|
44
|
+
details&.delete(:session)
|
45
|
+
|
46
|
+
# Create the params
|
47
|
+
params = { result: result, error: error, details: details }
|
48
|
+
|
49
|
+
# Push the response back
|
50
|
+
self.queue.push descriptor.handle, descriptor.command, params
|
51
|
+
}
|
52
|
+
|
53
|
+
# Call the session
|
54
|
+
if descriptor.command == :call
|
55
|
+
|
56
|
+
# invoke the call method
|
57
|
+
procedure = descriptor.params[:procedure]
|
58
|
+
args = descriptor.params[:args]
|
59
|
+
kwargs = descriptor.params[:kwargs]
|
60
|
+
options = descriptor.params[:options]
|
61
|
+
|
62
|
+
self.session.call(procedure, args, kwargs, options, &callback)
|
63
|
+
|
64
|
+
elsif descriptor.command == :publish
|
65
|
+
|
66
|
+
# invoke the publish method
|
67
|
+
topic = descriptor.params[:topic]
|
68
|
+
args = descriptor.params[:args]
|
69
|
+
kwargs = descriptor.params[:kwargs]
|
70
|
+
options = descriptor.params[:options]
|
71
|
+
|
72
|
+
self.session.publish(topic, args, kwargs, options, &callback)
|
73
|
+
|
74
|
+
elsif descriptor.command == :yield
|
75
|
+
|
76
|
+
# invoke the yield method
|
77
|
+
request = descriptor.params[:request]
|
78
|
+
options = descriptor.params[:options]
|
79
|
+
check_defer = descriptor.params[:check_defer]
|
80
|
+
result_hash = descriptor.params[:result] || {}
|
81
|
+
|
82
|
+
# Get the response from the descriptor params
|
83
|
+
result = Wamp::Client::Response.from_hash(result_hash)
|
84
|
+
|
85
|
+
self.session.yield(request, result, options, check_defer)
|
86
|
+
|
87
|
+
else
|
88
|
+
|
89
|
+
# Return error if the command is not supported
|
90
|
+
error = Wamp::Client::Response::CallError.new(
|
91
|
+
Wamp::Client::Response::DEFAULT_ERROR,
|
92
|
+
["unsupported proxy command '#{descriptor.command}'"])
|
93
|
+
callback.call(nil, error.to_hash, {})
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# This methods blocks waiting for a value to appear in the queue
|
102
|
+
#
|
103
|
+
# @param queue_name [String] - the name of the queue
|
104
|
+
def check_queue(queue_name)
|
105
|
+
|
106
|
+
# Wait for a value to appear in the queue. We have a timeout so
|
107
|
+
# the thread can check if the worker has been killed
|
108
|
+
self.queue.pop(queue_name, wait: true, timeout: TIMEOUT)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
|
3
|
+
module Wamp
|
4
|
+
module Worker
|
5
|
+
module Proxy
|
6
|
+
|
7
|
+
class Requestor < Base
|
8
|
+
|
9
|
+
# Performs the session "call" method
|
10
|
+
#
|
11
|
+
# @param procedure [String] - The procedure to call
|
12
|
+
# @param args [Array] - Array of arguments
|
13
|
+
# @param kwargs [Hash] - Hash of key/word arguments
|
14
|
+
# @param options [Hash] - Options for the call
|
15
|
+
def call(procedure, args=nil, kwargs=nil, options={}, &callback)
|
16
|
+
|
17
|
+
# Create the params
|
18
|
+
params = { procedure: procedure, args: args, kwargs: kwargs, options: options }
|
19
|
+
|
20
|
+
# Execute the command
|
21
|
+
request_response :call, params, true, &callback
|
22
|
+
end
|
23
|
+
|
24
|
+
# Performs the session "publish" method
|
25
|
+
#
|
26
|
+
# @param topic [String] - The topic to publish
|
27
|
+
# @param args [Array] - Array of arguments
|
28
|
+
# @param kwargs [Hash] - Hash of key/word arguments
|
29
|
+
# @param options [Hash] - Options for the subscribe
|
30
|
+
def publish(topic, args=nil, kwargs=nil, options={}, &callback)
|
31
|
+
|
32
|
+
# Create the params
|
33
|
+
params = { topic: topic , args: args, kwargs: kwargs, options: options }
|
34
|
+
|
35
|
+
# Execute the command
|
36
|
+
request_response :publish, params, options[:acknowledge], &callback
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Method to push the request and wait for the response
|
42
|
+
#
|
43
|
+
# @param command [Symbol] - The command
|
44
|
+
# @param params [Hash] - The parameters
|
45
|
+
# @param wait [Bool] - if true, will wait for the response
|
46
|
+
def request_response(command, params, wait=true)
|
47
|
+
|
48
|
+
# Create a response handle
|
49
|
+
handle = self.unique_command_resp_queue
|
50
|
+
|
51
|
+
# Push the request
|
52
|
+
self.queue.push self.command_req_queue, command, params, handle
|
53
|
+
|
54
|
+
# If wait, check the queue and respond
|
55
|
+
if wait
|
56
|
+
|
57
|
+
# Store the start ticker
|
58
|
+
start_tick = self.ticker.get
|
59
|
+
|
60
|
+
# Wait for the response
|
61
|
+
descriptor = self.queue.pop(handle, wait: true, delete: true)
|
62
|
+
|
63
|
+
# check for nil descriptor
|
64
|
+
if descriptor == nil
|
65
|
+
|
66
|
+
# If the ticker never incremented, throw a "worker not responding" error
|
67
|
+
current_tick = self.ticker.get
|
68
|
+
if start_tick == current_tick
|
69
|
+
raise(RuntimeError, "worker '#{self.name}' is not responding")
|
70
|
+
else
|
71
|
+
raise(RuntimeError, "request to #{handle} timed out")
|
72
|
+
end
|
73
|
+
|
74
|
+
else
|
75
|
+
|
76
|
+
# If a block was given, respond
|
77
|
+
if block_given?
|
78
|
+
response = [descriptor.params[:result], descriptor.params[:error], descriptor.params[:details]]
|
79
|
+
yield(*response)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Wamp
|
4
|
+
module Worker
|
5
|
+
|
6
|
+
class Queue
|
7
|
+
attr_reader :redis, :default_timeout
|
8
|
+
|
9
|
+
# This class represents the payload that will be stored in Redis
|
10
|
+
class Descriptor
|
11
|
+
attr_reader :command, :handle, :params
|
12
|
+
|
13
|
+
# Constructor
|
14
|
+
#
|
15
|
+
# @param command [Symbol] - The command for the descriptor
|
16
|
+
# @param handle [String] - The handle representing the descriptor
|
17
|
+
# @param params [Hash] - The params for the command
|
18
|
+
def initialize(command, handle, params)
|
19
|
+
@command = command.to_sym
|
20
|
+
@handle = handle
|
21
|
+
@params = params || {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# Create a Descriptor object from the json payload
|
25
|
+
#
|
26
|
+
# @param json_string [String] - The string from the Redis store
|
27
|
+
# @return [Descriptor] - The instantiated descriptor
|
28
|
+
def self.from_json(json_string)
|
29
|
+
return unless json_string
|
30
|
+
parsed = JSON.parse(json_string, :symbolize_names => true)
|
31
|
+
self.new(parsed[:command], parsed[:handle], parsed[:params])
|
32
|
+
end
|
33
|
+
|
34
|
+
# Creates the json payload from the object
|
35
|
+
#
|
36
|
+
# @return [String] - The string that will go into the Redis store
|
37
|
+
def to_json
|
38
|
+
{ command: self.command, handle: self.handle, params: self.params }.to_json
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Constructor
|
43
|
+
#
|
44
|
+
def initialize(name)
|
45
|
+
@redis = Wamp::Worker.config.redis(name)
|
46
|
+
@default_timeout = Wamp::Worker.config.timeout(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Pushes a command onto the queue
|
50
|
+
#
|
51
|
+
# @param queue_name [String] - The name of the queue
|
52
|
+
# @param command [Symbol] - The command
|
53
|
+
# @param params [Hash] - The params for the request
|
54
|
+
# @param handle [String] - The response handle
|
55
|
+
def push(queue_name, command, params, handle=nil)
|
56
|
+
|
57
|
+
# Create the descriptor
|
58
|
+
descriptor = Descriptor.new(command, handle, params)
|
59
|
+
|
60
|
+
# Log the info
|
61
|
+
log(:push, queue_name, descriptor)
|
62
|
+
|
63
|
+
# Queue the command
|
64
|
+
self.redis.lpush(queue_name, descriptor.to_json)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Pops a command off of the queue
|
68
|
+
#
|
69
|
+
# @param queue_name [String, Array] - The name of the queue (or multiple queues if brpop)
|
70
|
+
# @param wait [Bool] - True if we want to block waiting for the response
|
71
|
+
# @param delete [Bool] - True if we want the queue deleted (only applicable if wait)
|
72
|
+
# @param timeout [Int] - Number of seconds to wait before timing out
|
73
|
+
def pop(queue_name, wait: false, delete: false, timeout: nil)
|
74
|
+
|
75
|
+
# Retrieve the response from the queue
|
76
|
+
if wait
|
77
|
+
# Use the default timeout if non is specified
|
78
|
+
timeout ||= self.default_timeout
|
79
|
+
|
80
|
+
# Make the pop call
|
81
|
+
response = self.redis.brpop(queue_name, timeout: timeout)
|
82
|
+
|
83
|
+
# Returns [queue, value]
|
84
|
+
if response != nil
|
85
|
+
queue_name = response[0]
|
86
|
+
response = response[1]
|
87
|
+
end
|
88
|
+
else
|
89
|
+
# Else just call the method
|
90
|
+
response = self.redis.rpop(queue_name)
|
91
|
+
end
|
92
|
+
|
93
|
+
# If delete was set, delete the queue
|
94
|
+
if delete
|
95
|
+
self.redis.del(queue_name)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Parse the response
|
99
|
+
descriptor = response != nil ? Descriptor.from_json(response) : nil
|
100
|
+
|
101
|
+
# Log the info
|
102
|
+
log(:pop, queue_name, descriptor)
|
103
|
+
|
104
|
+
# Return the queue_name and the descriptor
|
105
|
+
descriptor
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
# Returns the logger
|
111
|
+
#
|
112
|
+
def logger
|
113
|
+
Wamp::Worker.logger
|
114
|
+
end
|
115
|
+
|
116
|
+
# Logs the info
|
117
|
+
#
|
118
|
+
def log(type, queue_name, descriptor)
|
119
|
+
return unless logger.level == Logger::DEBUG
|
120
|
+
|
121
|
+
if descriptor
|
122
|
+
logger.debug("#{self.class.name} #{type.upcase} : #{queue_name}")
|
123
|
+
logger.debug(" command: #{descriptor.command}")
|
124
|
+
logger.debug(" params: #{descriptor.params}")
|
125
|
+
logger.debug(" handle: #{descriptor.handle}")
|
126
|
+
else
|
127
|
+
logger.debug("#{self.class.name} #{type.upcase} : #{queue_name} : EMPTY")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Wamp
|
2
|
+
module Worker
|
3
|
+
module Rails
|
4
|
+
|
5
|
+
# This method will load Rails
|
6
|
+
#
|
7
|
+
# @param environment [String] - The Rails environment
|
8
|
+
# @param require [String] - The path to the Rails working directory or a file with requires
|
9
|
+
def self.load_app(environment, require)
|
10
|
+
ENV['RACK_ENV'] = ENV['RAILS_ENV'] = environment
|
11
|
+
|
12
|
+
raise ArgumentError, "'#{require}' does not exist" unless File.exist?(require)
|
13
|
+
|
14
|
+
if File.directory?(require)
|
15
|
+
require 'rails'
|
16
|
+
if ::Rails::VERSION::MAJOR < 5
|
17
|
+
raise "only Rails version 5 and higher supported"
|
18
|
+
else
|
19
|
+
require File.expand_path("#{require}/config/environment.rb")
|
20
|
+
end
|
21
|
+
else
|
22
|
+
require(require) || raise(ArgumentError, "no require file found at '#{require}'")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require "thread"
|
2
|
+
require "wamp/client/connection"
|
3
|
+
|
4
|
+
module Wamp
|
5
|
+
module Worker
|
6
|
+
module Runner
|
7
|
+
|
8
|
+
# This is a base class for all of the runners
|
9
|
+
class Base
|
10
|
+
attr_reader :name, :dispatcher
|
11
|
+
|
12
|
+
# Constructor
|
13
|
+
#
|
14
|
+
# @param name [Symbol] - the name of the worker
|
15
|
+
def initialize(name, uuid: nil)
|
16
|
+
# Initialize the dispatcher
|
17
|
+
@name = name || :default
|
18
|
+
@dispatcher = Proxy::Dispatcher.new(self.name, uuid: uuid)
|
19
|
+
@active = false
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the logger
|
23
|
+
#
|
24
|
+
def logger
|
25
|
+
Wamp::Worker.logger
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns if the runner is active
|
29
|
+
#
|
30
|
+
def active?
|
31
|
+
@active
|
32
|
+
end
|
33
|
+
|
34
|
+
# Starts the runner
|
35
|
+
#
|
36
|
+
def start
|
37
|
+
return if self.active?
|
38
|
+
@active = true
|
39
|
+
self._start
|
40
|
+
end
|
41
|
+
|
42
|
+
# Stops the runner
|
43
|
+
#
|
44
|
+
def stop
|
45
|
+
return unless self.active?
|
46
|
+
self._stop
|
47
|
+
@active = false
|
48
|
+
end
|
49
|
+
|
50
|
+
#region Override Methods
|
51
|
+
def _start
|
52
|
+
end
|
53
|
+
|
54
|
+
def _stop
|
55
|
+
end
|
56
|
+
#endregion
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# This class monitors the queue and returns the descriptor
|
61
|
+
class Background < Base
|
62
|
+
attr_reader :callback, :thread
|
63
|
+
|
64
|
+
# Constructor
|
65
|
+
#
|
66
|
+
# @param name [Symbol] - the name of the worker
|
67
|
+
def initialize(name, uuid: nil, &callback)
|
68
|
+
super name, uuid: uuid
|
69
|
+
|
70
|
+
@callback = callback
|
71
|
+
|
72
|
+
# Log the event
|
73
|
+
logger.debug("#{self.class.name} '#{self.name}' created")
|
74
|
+
end
|
75
|
+
|
76
|
+
# Starts the background runner
|
77
|
+
#
|
78
|
+
def _start
|
79
|
+
# Start the background thread
|
80
|
+
Thread.new do
|
81
|
+
|
82
|
+
# The background thread will infinitely call the callback while the
|
83
|
+
# runner is active
|
84
|
+
while self.active?
|
85
|
+
begin
|
86
|
+
self.callback.call(self)
|
87
|
+
rescue => e
|
88
|
+
logger.error("#{self.class.name} #{e.class.name} - #{e.message}")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# This class is the main runner
|
97
|
+
class Main < Base
|
98
|
+
attr_reader :challenge, :client, :descriptor_queue, :queue_monitor
|
99
|
+
|
100
|
+
# Constructor
|
101
|
+
#
|
102
|
+
def initialize(name=nil, **options)
|
103
|
+
super name
|
104
|
+
|
105
|
+
# Combine the options
|
106
|
+
options = Wamp::Worker.config.connection(self.name).merge options
|
107
|
+
|
108
|
+
# Setup different options
|
109
|
+
@challenge = options[:challenge]
|
110
|
+
@client = options[:client] || Wamp::Client::Connection.new(options)
|
111
|
+
@active = false
|
112
|
+
|
113
|
+
# Log the event
|
114
|
+
logger.info("#{self.class.name} '#{self.name}' created with options")
|
115
|
+
logger.info(" uri: #{options[:uri]}")
|
116
|
+
logger.info(" realm: #{options[:realm]}")
|
117
|
+
|
118
|
+
# Create a queue for passing messages to the main runner
|
119
|
+
@descriptor_queue = ::Queue.new
|
120
|
+
|
121
|
+
# Note: since the queue monitor is attached to the same worker,
|
122
|
+
# we need to lock the UUIDs together. This will make sure they
|
123
|
+
# delegate background tasks correctly
|
124
|
+
uuid = self.dispatcher.uuid
|
125
|
+
|
126
|
+
# Create a command queue monitor
|
127
|
+
@queue_monitor = Background.new(self.name, uuid: uuid) do |runner|
|
128
|
+
descriptor = runner.dispatcher.check_queues
|
129
|
+
self.descriptor_queue.push(descriptor) if descriptor
|
130
|
+
end
|
131
|
+
|
132
|
+
# Add the tick loop handler
|
133
|
+
self.client.transport_class.add_tick_loop { self.tick_handler }
|
134
|
+
|
135
|
+
# Initialize the last tick
|
136
|
+
@last_tick = Time.now.to_i
|
137
|
+
|
138
|
+
# Catch SIGINT
|
139
|
+
Signal.trap('INT') { self.stop }
|
140
|
+
Signal.trap('TERM') { self.stop }
|
141
|
+
end
|
142
|
+
|
143
|
+
# Starts the run loop
|
144
|
+
#
|
145
|
+
def _start
|
146
|
+
|
147
|
+
# On join, we need to subscribe and register the different handlers
|
148
|
+
self.client.on :join do |session, details|
|
149
|
+
self.join_handler session, details
|
150
|
+
end
|
151
|
+
|
152
|
+
# On leave, we will print a message
|
153
|
+
self.client.on :leave do |reason, details|
|
154
|
+
self.leave_handler(reason, details)
|
155
|
+
end
|
156
|
+
|
157
|
+
# On challenge, we will run the users challenge code
|
158
|
+
self.client.on :challenge do |authmethod, details|
|
159
|
+
self.challenge_handler(authmethod, details)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Start the monitors
|
163
|
+
self.queue_monitor.start
|
164
|
+
|
165
|
+
# Log info
|
166
|
+
logger.info("#{self.class.name} '#{self.name}' started")
|
167
|
+
|
168
|
+
# Start the connection
|
169
|
+
self.client.open
|
170
|
+
end
|
171
|
+
|
172
|
+
# Stops the run loop
|
173
|
+
#
|
174
|
+
def _stop
|
175
|
+
|
176
|
+
# Stop the other threads
|
177
|
+
self.queue_monitor.stop
|
178
|
+
|
179
|
+
# Stop the event machine
|
180
|
+
self.client.close
|
181
|
+
end
|
182
|
+
|
183
|
+
def join_handler(session, details)
|
184
|
+
logger.info("#{self.class.name} runner '#{self.name}' joined session with realm '#{details[:realm]}'")
|
185
|
+
|
186
|
+
# Set the session
|
187
|
+
self.dispatcher.session = session
|
188
|
+
|
189
|
+
# Register for the procedures
|
190
|
+
Wamp::Worker.register_procedures(self.name, self.dispatcher, session)
|
191
|
+
|
192
|
+
# Subscribe to the topics
|
193
|
+
Wamp::Worker.subscribe_topics(self.name, self.dispatcher, session)
|
194
|
+
end
|
195
|
+
|
196
|
+
def leave_handler(reason, details)
|
197
|
+
logger.info("#{self.class.name} runner '#{self.name}' left session: #{reason}")
|
198
|
+
|
199
|
+
# Clear the session
|
200
|
+
self.dispatcher.session = nil
|
201
|
+
end
|
202
|
+
|
203
|
+
def challenge_handler(authmethod, extra)
|
204
|
+
logger.info("#{self.class.name} runner '#{self.name}' challenge")
|
205
|
+
|
206
|
+
if self.challenge
|
207
|
+
self.challenge.call(authmethod, extra)
|
208
|
+
else
|
209
|
+
self.stop
|
210
|
+
raise(ArgumentError, "client asked for '#{authmethod}' challenge, but no ':challenge' option was provided")
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# This method periodically checks if any work has come in from the queues
|
215
|
+
#
|
216
|
+
def tick_handler
|
217
|
+
|
218
|
+
# This code will implement the ticker every second. This tells the
|
219
|
+
# requestors that the worker is alive
|
220
|
+
current_time = Time.now.to_i
|
221
|
+
if current_time > @last_tick
|
222
|
+
self.dispatcher.increment_ticker
|
223
|
+
@last_tick = current_time
|
224
|
+
end
|
225
|
+
|
226
|
+
# Loop until the queue is empty
|
227
|
+
until self.descriptor_queue.empty? do
|
228
|
+
|
229
|
+
# Pop the value and process it
|
230
|
+
descriptor = self.descriptor_queue.pop
|
231
|
+
self.dispatcher.process(descriptor)
|
232
|
+
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|