short_bus 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/README.md +19 -19
- data/examples/misc_tests +16 -16
- data/examples/tutorial_1_basic_intro.rb +6 -6
- data/examples/tutorial_2_message_return_values.rb +5 -5
- data/lib/short_bus/debug_message.rb +3 -1
- data/lib/short_bus/driver.rb +27 -18
- data/lib/short_bus/message.rb +14 -12
- data/lib/short_bus/monitor.rb +8 -8
- data/lib/short_bus/service.rb +16 -14
- data/lib/short_bus/spec.rb +6 -4
- data/lib/short_bus/version.rb +1 -1
- data/lib/short_bus.rb +3 -1
- metadata +14 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f681095e57013c065264397ad260ad230f2aa84b
|
|
4
|
+
data.tar.gz: 11338f735f7c245fee57f10d90818580ec38cc72
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a51b49ee774d846b2e3514767eacf4d40d6e5e120e53039613875b76e48ef5e08cbc93961a6ce59d111462422abf6a710a8f956a23b22e254a57c673bc07887
|
|
7
|
+
data.tar.gz: 87711efa87603007cac0b8ac4f741d2ce06f36144985b8bed0e0496aba70f5d724cac5748f3a4452b9c8fa4cda0a42bd5dc4f21be6f306e8615d245d2820139f
|
data/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# ShortBus
|
|
2
|
-
|
|
2
|
+
Lightweight multi-threaded pub-sub message dispatcher for implementing self-contained service-oriented Ruby apps.
|
|
3
3
|
|
|
4
4
|
## What does it do?
|
|
5
|
-
The goal is to provide a
|
|
5
|
+
The goal is to provide a lightweight message dispatcher/service API, with multi-threaded message publishing and subscription for closures (Lambdas/Blocks) and Methods.
|
|
6
6
|
|
|
7
|
-
ShortBus has no dependencies outside of the Ruby Core & Standard Libraries.
|
|
7
|
+
ShortBus has no dependencies outside of the Ruby Core & Standard Libraries, and has less than 300 lines of code.
|
|
8
8
|
|
|
9
9
|
## What are the components?
|
|
10
10
|
A service is a participant in the SOA (Service Oriented Architecture) for publishing and/or subscribing to messages. To receive messages, the service subscribes to the Driver (Driver#subscribe); and is run as a callback in a dedicated thread or thread pool.
|
|
@@ -14,16 +14,16 @@ A message (as simple as a String, but ultimately converted to a ShortBus::Messag
|
|
|
14
14
|
The Driver (ShortBus::Driver) is the brains of the operation. Once instantiated, a dedicated thread monitors the incoming queue, converts and routes the messages to the appropriate subscribers based on the message\_spec(s) supplied at the time of subscription.
|
|
15
15
|
|
|
16
16
|
## What does a message and a message\_spec look like?
|
|
17
|
-
In it's simplest form, a message can be a simple String like `'shutdown'`, but typically a more flexible, component based format is used, delimited by
|
|
17
|
+
In it's simplest form, a message can be a simple String like `'shutdown'`, but typically a more flexible, component based format is used, delimited by `/`, like `'OwnerService/Action/Argument'`. The Driver will convert the message String into a ShortBus::Message object before routing.
|
|
18
18
|
|
|
19
|
-
A message\_spec can be supplied when subscribing in order to select which messages are received (ie: run the callback). A message\_spec can be a String (`'shutdown'`), a wildcard String (`'OwnerService
|
|
19
|
+
A message\_spec can be supplied when subscribing in order to select which messages are received (ie: run the callback). A message\_spec can be a String (`'shutdown'`), a wildcard String (`'OwnerService/**'`), a Regexp, or even an Array or Set of multiple Strings and/or Regexps.
|
|
20
20
|
|
|
21
21
|
#### Wildcard String?
|
|
22
|
-
To simplify filtering, a message\_spec String can contain a `*` or a `**` wildcard. A `*` wildcard matches just one field between
|
|
22
|
+
To simplify filtering, a message\_spec String can contain a `*` or a `**` wildcard. A `*` wildcard matches just one field between `/` delimiters. A `**` wildcard matches one or more.
|
|
23
23
|
|
|
24
|
-
`'Service
|
|
24
|
+
`'Service/*'` matches `'Service/Start'`, but not `'Service/Start/Now'`
|
|
25
25
|
|
|
26
|
-
`'Service
|
|
26
|
+
`'Service/**'` matches both `'Service/Start'` and `'Service/Start/Now'`
|
|
27
27
|
|
|
28
28
|
Wilcard Strings are turned into Regexps by the Driver.
|
|
29
29
|
|
|
@@ -35,7 +35,7 @@ When a new Message is published via the Driver#publish method, the return value
|
|
|
35
35
|
The publisher can then #pop from that Message, which will block and wait for one of the subscribers to #push a "return value" into the Message on the other side. To make things more flexible, #pop (and #shift, #deq) has been extended to accept a numeric value, which acts as a timeout in seconds.
|
|
36
36
|
|
|
37
37
|
```ruby
|
|
38
|
-
return_val = driver.publish('Testing
|
|
38
|
+
return_val = driver.publish('Testing/Message')
|
|
39
39
|
.pop(3)
|
|
40
40
|
```
|
|
41
41
|
|
|
@@ -57,38 +57,38 @@ driver.subscribe { |message| puts "1. I like all foods, including #{message}" }
|
|
|
57
57
|
# Subscribes a block with a message_spec filtering only some messages
|
|
58
58
|
# Also, replies back to the driver with a new message.
|
|
59
59
|
#
|
|
60
|
-
driver.subscribe(message_spec: 'Chocolate
|
|
60
|
+
driver.subscribe(message_spec: 'Chocolate/**') do |message|
|
|
61
61
|
puts "2. Did I hear you say Chocolate? (#{message}). I know what I'm making."
|
|
62
|
-
'Chocolate
|
|
62
|
+
'Chocolate/And/Strawberries'
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
# Subscribes a block with a message_spec filtering only some messages
|
|
66
66
|
#
|
|
67
|
-
driver.subscribe(message_spec: '
|
|
67
|
+
driver.subscribe(message_spec: '**/Strawberries') do |message|
|
|
68
68
|
puts "3. I only care about Strawberries: #{message}"
|
|
69
69
|
'Strawberries'
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
# First lets just test it with an unrelated message
|
|
73
73
|
#
|
|
74
|
-
driver.publish 'Cookies
|
|
74
|
+
driver.publish 'Cookies/And/Cream'
|
|
75
75
|
sleep 0.1
|
|
76
76
|
puts
|
|
77
77
|
|
|
78
78
|
# Now lets try some interaction going between services
|
|
79
79
|
#
|
|
80
|
-
driver.publish 'Chocolate
|
|
80
|
+
driver.publish 'Chocolate/Anything'
|
|
81
81
|
sleep 0.1
|
|
82
82
|
```
|
|
83
83
|
And here's what it looks like when we run it:
|
|
84
84
|
|
|
85
85
|
```
|
|
86
|
-
1. I like all foods, including Cookies
|
|
86
|
+
1. I like all foods, including Cookies/And/Cream
|
|
87
87
|
|
|
88
|
-
1. I like all foods, including Chocolate
|
|
89
|
-
2. Did I hear you say Chocolate? (Chocolate
|
|
90
|
-
1. I like all foods, including Chocolate
|
|
91
|
-
3. I only care about Strawberries: Chocolate
|
|
88
|
+
1. I like all foods, including Chocolate/Anything
|
|
89
|
+
2. Did I hear you say Chocolate? (Chocolate/Anything). I know what I'm making.
|
|
90
|
+
1. I like all foods, including Chocolate/And/Strawberries
|
|
91
|
+
3. I only care about Strawberries: Chocolate/And/Strawberries
|
|
92
92
|
1. I like all foods, including Strawberries
|
|
93
93
|
```
|
|
94
94
|
|
data/examples/misc_tests
CHANGED
|
@@ -5,21 +5,21 @@ require 'short_bus'
|
|
|
5
5
|
|
|
6
6
|
driver = ShortBus::Driver.new(debug: false)
|
|
7
7
|
|
|
8
|
-
#monitor = ShortBus::Monitor.new driver
|
|
8
|
+
# monitor = ShortBus::Monitor.new driver
|
|
9
9
|
|
|
10
10
|
driver.subscribe(
|
|
11
11
|
name: 'lambie',
|
|
12
|
-
service: lambda
|
|
12
|
+
service: lambda do |_message|
|
|
13
13
|
sleep 0.2
|
|
14
|
-
raise
|
|
15
|
-
'lambie
|
|
16
|
-
|
|
14
|
+
raise StandardError, 'random explosion' if rand(4) == 0
|
|
15
|
+
'lambie/response'
|
|
16
|
+
end
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
driver.subscribe(
|
|
20
|
-
debug: false,
|
|
21
|
-
name: 'got',
|
|
22
|
-
publisher_spec: 'lambie',
|
|
20
|
+
debug: false,
|
|
21
|
+
name: 'got',
|
|
22
|
+
publisher_spec: 'lambie',
|
|
23
23
|
thread_count: 2
|
|
24
24
|
) do |msg|
|
|
25
25
|
sleep 0.3
|
|
@@ -35,21 +35,21 @@ driver.subscribe(
|
|
|
35
35
|
puts " payload: #{message.payload}" if message.payload
|
|
36
36
|
message << 'arbitrary object sent via Message'
|
|
37
37
|
message.payload += 1 if message.payload.is_a?(Numeric)
|
|
38
|
-
message.merge 'new
|
|
38
|
+
message.merge 'new/message'
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
Thread.new
|
|
42
|
-
5.times do
|
|
43
|
-
driver <<
|
|
41
|
+
Thread.new do
|
|
42
|
+
5.times do
|
|
43
|
+
driver << 'publish/thread'
|
|
44
44
|
sleep 0.15
|
|
45
45
|
end
|
|
46
|
-
|
|
46
|
+
end
|
|
47
47
|
|
|
48
|
-
first_message = driver << [
|
|
48
|
+
first_message = driver << ['hi/bob', 1]
|
|
49
49
|
sleep 0.2
|
|
50
|
-
driver << [
|
|
50
|
+
driver << ['hello/jim', 'pot']
|
|
51
51
|
sleep 0.2
|
|
52
|
-
driver << [
|
|
52
|
+
driver << ['hola/xxx', 'stew']
|
|
53
53
|
|
|
54
54
|
puts "Shift-back from first message #{first_message.shift(2)}"
|
|
55
55
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# First example - basic publishing / subscription
|
|
4
4
|
#
|
|
5
|
-
|
|
5
|
+
require 'short_bus'
|
|
6
6
|
|
|
7
7
|
# Instantiate Driver, start message routing thread
|
|
8
8
|
#
|
|
@@ -15,25 +15,25 @@ driver.subscribe { |message| puts "1. I like all foods, including #{message}" }
|
|
|
15
15
|
# Subscribes a block with a message_spec filtering only some messages
|
|
16
16
|
# Also, replies back to the driver with a new message.
|
|
17
17
|
#
|
|
18
|
-
driver.subscribe(message_spec: 'Chocolate
|
|
18
|
+
driver.subscribe(message_spec: 'Chocolate/**') do |message|
|
|
19
19
|
puts "2. Did I hear you say Chocolate? (#{message}). I know what I'm making."
|
|
20
|
-
'Chocolate
|
|
20
|
+
'Chocolate/And/Strawberries'
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# Subscribes a block with a message_spec filtering only some messages
|
|
24
24
|
#
|
|
25
|
-
driver.subscribe(message_spec: '
|
|
25
|
+
driver.subscribe(message_spec: '**/Strawberries') do |message|
|
|
26
26
|
puts "3. I only care about Strawberries: #{message}"
|
|
27
27
|
'Strawberries'
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
# First lets just test it with an unrelated message
|
|
31
31
|
#
|
|
32
|
-
driver.publish 'Cookies
|
|
32
|
+
driver.publish 'Cookies/And/Cream'
|
|
33
33
|
sleep 0.1
|
|
34
34
|
puts
|
|
35
35
|
|
|
36
36
|
# Now lets try some interaction going between services
|
|
37
37
|
#
|
|
38
|
-
driver.publish 'Chocolate
|
|
38
|
+
driver.publish 'Chocolate/Anything'
|
|
39
39
|
sleep 0.1
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
#
|
|
3
3
|
# ShortBus example passing return values via Message object
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
require 'short_bus'
|
|
6
6
|
|
|
7
7
|
driver = ShortBus::Driver.new
|
|
8
8
|
|
|
9
9
|
def house_cleaner(message)
|
|
10
|
-
puts
|
|
10
|
+
puts 'Lets blow this popsicle stand...'
|
|
11
11
|
sleep 0.5
|
|
12
12
|
|
|
13
13
|
# Send value back into the Message object
|
|
14
|
-
message <<
|
|
14
|
+
message << 'I\'m working on it!'
|
|
15
15
|
|
|
16
16
|
# pause
|
|
17
17
|
sleep 1
|
|
@@ -21,12 +21,12 @@ def house_cleaner(message)
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
driver.subscribe(
|
|
24
|
-
message_spec: '
|
|
24
|
+
message_spec: '*/Shutdown',
|
|
25
25
|
service: method(:house_cleaner)
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
# driver.publish returns the message object we just sent
|
|
29
|
-
our_message = driver.publish('Everyone
|
|
29
|
+
our_message = driver.publish('Everyone/Shutdown')
|
|
30
30
|
|
|
31
31
|
# Since it is inherited from a Queue, we can pop right off it
|
|
32
32
|
return_value = our_message.shift
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
##
|
|
2
|
+
# module method for outputting debugging messages
|
|
1
3
|
module DebugMessage
|
|
2
4
|
def debug_message(message)
|
|
3
5
|
(@debug_message_output_filehandle || STDERR).printf(
|
|
4
6
|
"%s::%s\n",
|
|
5
|
-
caller.first.sub(
|
|
7
|
+
caller.first.sub(%r{^.*/([^:]*).*}, '\1'),
|
|
6
8
|
message
|
|
7
9
|
) if @debug
|
|
8
10
|
end
|
data/lib/short_bus/driver.rb
CHANGED
|
@@ -2,6 +2,8 @@ require 'pp'
|
|
|
2
2
|
require 'set'
|
|
3
3
|
|
|
4
4
|
module ShortBus
|
|
5
|
+
##
|
|
6
|
+
# ShorBus::Driver is the message dispatcher.
|
|
5
7
|
class Driver
|
|
6
8
|
include DebugMessage
|
|
7
9
|
|
|
@@ -13,9 +15,13 @@ module ShortBus
|
|
|
13
15
|
default_message_spec: nil,
|
|
14
16
|
default_publisher_spec: nil,
|
|
15
17
|
default_thread_count: 1,
|
|
16
|
-
max_message_queue_size: 1_000_000
|
|
17
|
-
}
|
|
18
|
+
max_message_queue_size: 1_000_000
|
|
19
|
+
}.freeze
|
|
18
20
|
|
|
21
|
+
# Example:
|
|
22
|
+
#
|
|
23
|
+
# Arguments:
|
|
24
|
+
# options: hash
|
|
19
25
|
def initialize(*options)
|
|
20
26
|
@options = DEFAULT_DRIVER_OPTIONS
|
|
21
27
|
@options.merge! options[0] if options[0].is_a?(Hash)
|
|
@@ -26,6 +32,11 @@ module ShortBus
|
|
|
26
32
|
@threads = { message_router: launch_message_router }
|
|
27
33
|
end
|
|
28
34
|
|
|
35
|
+
# Subscribes a callback (lamba, block, method) to receive messages
|
|
36
|
+
#
|
|
37
|
+
# @param [*args]
|
|
38
|
+
# @return [ShortBus::Service] Service object that was created and registered
|
|
39
|
+
#
|
|
29
40
|
def subscribe(*args, &block)
|
|
30
41
|
service_args = {
|
|
31
42
|
debug: @debug,
|
|
@@ -34,7 +45,7 @@ module ShortBus
|
|
|
34
45
|
name: nil,
|
|
35
46
|
publisher_spec: @options[:default_publisher_spec],
|
|
36
47
|
service: nil,
|
|
37
|
-
thread_count: @options[:default_thread_count]
|
|
48
|
+
thread_count: @options[:default_thread_count]
|
|
38
49
|
}.merge args[0].is_a?(Hash) ? args[0] : { service: args[0] }
|
|
39
50
|
|
|
40
51
|
service_args[:service] = block.to_proc if block_given?
|
|
@@ -43,25 +54,24 @@ module ShortBus
|
|
|
43
54
|
@services[service.to_s] = service
|
|
44
55
|
end
|
|
45
56
|
|
|
46
|
-
def publish(publisher=nil
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
end
|
|
57
|
+
def publish(arg, publisher = nil)
|
|
58
|
+
return unless (message = convert_to_message arg)
|
|
59
|
+
message.publisher = publisher if publisher
|
|
60
|
+
@messages.push message
|
|
61
|
+
message
|
|
52
62
|
end
|
|
53
63
|
|
|
54
|
-
|
|
64
|
+
alias << publish
|
|
55
65
|
|
|
56
66
|
def unsubscribe(service)
|
|
57
67
|
if service.is_a? ShortBus::Service
|
|
58
68
|
unsubscribe service.to_s
|
|
59
|
-
elsif @services.
|
|
69
|
+
elsif @services.key?(service)
|
|
60
70
|
@services[service].stop
|
|
61
71
|
@services.delete service
|
|
62
|
-
end
|
|
72
|
+
end
|
|
63
73
|
end
|
|
64
|
-
|
|
74
|
+
|
|
65
75
|
private
|
|
66
76
|
|
|
67
77
|
def convert_to_message(arg)
|
|
@@ -71,16 +81,16 @@ module ShortBus
|
|
|
71
81
|
Message.new(arg)
|
|
72
82
|
elsif arg.is_a?(Array) && arg[0].is_a?(String)
|
|
73
83
|
Message.new(arg)
|
|
74
|
-
elsif arg.is_a?(Hash) && arg.
|
|
75
|
-
publisher = arg.
|
|
76
|
-
payload = arg.
|
|
84
|
+
elsif arg.is_a?(Hash) && arg.key?(:message) && arg[:message]
|
|
85
|
+
publisher = arg.key?(:publisher) ? arg[:publisher] : nil
|
|
86
|
+
payload = arg.key?(:payload) ? arg[:payload] : nil
|
|
77
87
|
Message.new(message: arg[:message], payload: payload, publisher: publisher)
|
|
78
88
|
end
|
|
79
89
|
end
|
|
80
90
|
|
|
81
91
|
def launch_message_router
|
|
82
92
|
Thread.new do
|
|
83
|
-
loop do
|
|
93
|
+
loop do
|
|
84
94
|
message = @messages.shift
|
|
85
95
|
debug_message "route_message(#{message})"
|
|
86
96
|
@services.values.each { |service| service.check message }
|
|
@@ -89,4 +99,3 @@ module ShortBus
|
|
|
89
99
|
end
|
|
90
100
|
end
|
|
91
101
|
end
|
|
92
|
-
|
data/lib/short_bus/message.rb
CHANGED
|
@@ -7,6 +7,8 @@ require 'timeout'
|
|
|
7
7
|
# - publisher (string or nil = anonymous)
|
|
8
8
|
#
|
|
9
9
|
module ShortBus
|
|
10
|
+
##
|
|
11
|
+
# ShortBus::Message is the object which is published & received by services
|
|
10
12
|
class Message < Queue
|
|
11
13
|
attr_accessor :publisher
|
|
12
14
|
attr_reader :payload
|
|
@@ -17,16 +19,16 @@ module ShortBus
|
|
|
17
19
|
if populate args
|
|
18
20
|
super()
|
|
19
21
|
else
|
|
20
|
-
raise ArgumentError
|
|
22
|
+
raise ArgumentError, "#Message: Invalid args #{args.pretty_inspect}"
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def merge(*args)
|
|
25
27
|
arg_hash = process_args args
|
|
26
|
-
if arg_hash[:message]
|
|
28
|
+
if arg_hash[:message]
|
|
27
29
|
Message.new(
|
|
28
30
|
message: arg_hash[:message] || @message,
|
|
29
|
-
payload: arg_hash.
|
|
31
|
+
payload: arg_hash.key?(:payload) ? arg_hash[:payload] : @payload
|
|
30
32
|
)
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -35,7 +37,7 @@ module ShortBus
|
|
|
35
37
|
@semaphore.synchronize { @payload = arg }
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
def pop(time_out=nil)
|
|
40
|
+
def pop(time_out = nil)
|
|
39
41
|
if time_out.is_a? Numeric
|
|
40
42
|
begin
|
|
41
43
|
Timeout.timeout(time_out) { super() }
|
|
@@ -46,8 +48,8 @@ module ShortBus
|
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
alias shift pop
|
|
52
|
+
alias deq pop
|
|
51
53
|
|
|
52
54
|
def to_s
|
|
53
55
|
@message
|
|
@@ -57,9 +59,9 @@ module ShortBus
|
|
|
57
59
|
|
|
58
60
|
def populate(args)
|
|
59
61
|
arg_hash = process_args args
|
|
60
|
-
if arg_hash.
|
|
61
|
-
@payload = arg_hash[:payload] if arg_hash.
|
|
62
|
-
@publisher = arg_hash[:publisher] if arg_hash.
|
|
62
|
+
if arg_hash.key?(:message)
|
|
63
|
+
@payload = arg_hash[:payload] if arg_hash.key?(:payload)
|
|
64
|
+
@publisher = arg_hash[:publisher] if arg_hash.key?(:publisher)
|
|
63
65
|
@message = arg_hash[:message]
|
|
64
66
|
end
|
|
65
67
|
end
|
|
@@ -73,9 +75,9 @@ module ShortBus
|
|
|
73
75
|
me[:payload] = args[1] if args.length == 2
|
|
74
76
|
me[:payload] = args.slice(1..-1) if args.length > 2
|
|
75
77
|
me[:message] = args[0]
|
|
76
|
-
elsif args[0].is_a?(Hash) && args[0].
|
|
77
|
-
me[:payload] = args[0][:payload] if args[0].
|
|
78
|
-
me[:publisher] = args[0][:publisher] if args[0].
|
|
78
|
+
elsif args[0].is_a?(Hash) && args[0].key?(:message)
|
|
79
|
+
me[:payload] = args[0][:payload] if args[0].key?(:payload)
|
|
80
|
+
me[:publisher] = args[0][:publisher] if args[0].key?(:publisher)
|
|
79
81
|
me[:message] = args[0][:message]
|
|
80
82
|
end
|
|
81
83
|
end
|
data/lib/short_bus/monitor.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
require 'pp'
|
|
2
2
|
|
|
3
3
|
module ShortBus
|
|
4
|
+
##
|
|
5
|
+
# For printing out all messages
|
|
4
6
|
class Monitor
|
|
5
7
|
|
|
6
8
|
DEFAULT_MONITOR_OPTIONS = {
|
|
@@ -10,15 +12,13 @@ module ShortBus
|
|
|
10
12
|
suppress_publisher: false,
|
|
11
13
|
publisher_spec: nil,
|
|
12
14
|
thread_count: 1
|
|
13
|
-
}
|
|
15
|
+
}.freeze
|
|
14
16
|
|
|
15
17
|
def initialize(*args)
|
|
16
|
-
@options = DEFAULT_MONITOR_OPTIONS.merge(
|
|
17
|
-
{ service: method(:monitor) }
|
|
18
|
-
)
|
|
18
|
+
@options = DEFAULT_MONITOR_OPTIONS.merge(service: method(:monitor))
|
|
19
19
|
@suppress_payload, @suppress_publisher = nil
|
|
20
20
|
|
|
21
|
-
if args[0].is_a?(Hash) && args[0].
|
|
21
|
+
if args[0].is_a?(Hash) && args[0].key?(:driver)
|
|
22
22
|
@options.merge! args[0]
|
|
23
23
|
@driver = @options[:driver]
|
|
24
24
|
@options.delete(:driver)
|
|
@@ -38,14 +38,14 @@ module ShortBus
|
|
|
38
38
|
puts "[#{@options[:name]}] message = #{message}"
|
|
39
39
|
printf(
|
|
40
40
|
" %s payload = %s\n",
|
|
41
|
-
@options[:name] ?
|
|
41
|
+
@options[:name] ? ' ' * @options[:name].length : '',
|
|
42
42
|
message.payload.inspect
|
|
43
43
|
) if message.payload && !@suppress_payload
|
|
44
44
|
printf(
|
|
45
45
|
" %spublisher = %s\n",
|
|
46
|
-
@options[:name] ?
|
|
46
|
+
@options[:name] ? ' ' * @options[:name].length : '',
|
|
47
47
|
message.publisher ? message.publisher : '*ANONYMOUS*'
|
|
48
|
-
)
|
|
48
|
+
) unless @suppress_publisher
|
|
49
49
|
nil
|
|
50
50
|
end
|
|
51
51
|
|
data/lib/short_bus/service.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
#require 'observer'
|
|
2
1
|
require 'pp'
|
|
3
2
|
require 'set'
|
|
4
3
|
require 'openssl'
|
|
5
4
|
|
|
6
5
|
module ShortBus
|
|
6
|
+
##
|
|
7
|
+
# ShortBus::Service tracks a registered service (subscriber)
|
|
7
8
|
class Service
|
|
8
9
|
include DebugMessage
|
|
9
10
|
|
|
@@ -17,7 +18,7 @@ module ShortBus
|
|
|
17
18
|
name: nil,
|
|
18
19
|
recursive: false,
|
|
19
20
|
publisher_spec: nil,
|
|
20
|
-
service: nil,
|
|
21
|
+
service: nil,
|
|
21
22
|
suppress_exception: false,
|
|
22
23
|
thread_count: 1
|
|
23
24
|
)
|
|
@@ -27,6 +28,7 @@ module ShortBus
|
|
|
27
28
|
@recursive = recursive
|
|
28
29
|
@publisher_spec = publisher_spec ? Spec.new(publisher_spec) : nil
|
|
29
30
|
@service = service
|
|
31
|
+
@suppress_exception = suppress_exception
|
|
30
32
|
@thread_count = thread_count
|
|
31
33
|
|
|
32
34
|
@name = name || @service.to_s || OpenSSL::HMAC.new(rand.to_s, 'sha1').to_s
|
|
@@ -34,9 +36,9 @@ module ShortBus
|
|
|
34
36
|
@threads = []
|
|
35
37
|
start
|
|
36
38
|
end
|
|
37
|
-
|
|
38
|
-
def check(message, dry_run=false)
|
|
39
|
-
debug_message "[#{@name}]#check(#{message})#{' dry_run' if dry_run}#"
|
|
39
|
+
|
|
40
|
+
def check(message, dry_run = false)
|
|
41
|
+
debug_message "[#{@name}]#check(#{message})#{' dry_run' if dry_run}#"
|
|
40
42
|
if(
|
|
41
43
|
(!@message_spec || @message_spec.match(message.to_s)) &&
|
|
42
44
|
(!@publisher_spec || @publisher_spec.match(message.publisher)) &&
|
|
@@ -49,22 +51,22 @@ module ShortBus
|
|
|
49
51
|
# TODO: consider some mechanism to pass Exceptions up to the main thread,
|
|
50
52
|
# perhaps with a whitelist, optional logging, something clean.
|
|
51
53
|
def service_thread
|
|
52
|
-
Thread.new do
|
|
54
|
+
Thread.new do
|
|
53
55
|
begin
|
|
54
|
-
run_service @run_queue.shift until Thread.current.key?(:stop)
|
|
56
|
+
run_service @run_queue.shift until Thread.current.key?(:stop)
|
|
55
57
|
rescue Exception => exc
|
|
56
58
|
puts "Service [#{@name}] => #{exc.inspect}" unless @suppress_exception
|
|
57
59
|
abort if exc.is_a? SystemExit
|
|
58
60
|
retry unless Thread.current.key?(:stop)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
def start
|
|
64
66
|
@threads << service_thread while @threads.length < @thread_count
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
def stop(when_to_kill=nil)
|
|
69
|
+
def stop(when_to_kill = nil)
|
|
68
70
|
@threads.each do |thread|
|
|
69
71
|
if when_to_kill.is_a? Numeric
|
|
70
72
|
begin
|
|
@@ -72,13 +74,13 @@ module ShortBus
|
|
|
72
74
|
rescue Timeout::Error
|
|
73
75
|
stop :now
|
|
74
76
|
end
|
|
75
|
-
elsif when_to_kill == :now
|
|
77
|
+
elsif when_to_kill == :now
|
|
76
78
|
thread.kill
|
|
77
79
|
else
|
|
78
80
|
thread[:stop] = true
|
|
79
81
|
end
|
|
80
82
|
end
|
|
81
|
-
@threads.delete_if
|
|
83
|
+
@threads.delete_if(&:join)
|
|
82
84
|
end
|
|
83
85
|
|
|
84
86
|
def stop!
|
|
@@ -95,9 +97,9 @@ module ShortBus
|
|
|
95
97
|
debug_message "[#{@name}]#run_service(#{message}) -> #{@service.class.name} ##{@service.arity}"
|
|
96
98
|
if @service.is_a?(Proc) || @service.is_a?(Method)
|
|
97
99
|
if @service.arity == 0
|
|
98
|
-
@driver.publish(@
|
|
100
|
+
@driver.publish(@service.call, @name)
|
|
99
101
|
elsif [1, -1, -2].include? @service.arity
|
|
100
|
-
@driver.publish(@
|
|
102
|
+
@driver.publish(@service.call(message), @name)
|
|
101
103
|
else
|
|
102
104
|
raise ArgumentError, "Service invalid arg count: #{@service.class.name}"
|
|
103
105
|
end
|
data/lib/short_bus/spec.rb
CHANGED
|
@@ -2,6 +2,8 @@ require 'pp'
|
|
|
2
2
|
require 'set'
|
|
3
3
|
|
|
4
4
|
module ShortBus
|
|
5
|
+
##
|
|
6
|
+
# Used for message_specs and publisher_specs
|
|
5
7
|
class Spec
|
|
6
8
|
attr_reader :specs
|
|
7
9
|
|
|
@@ -18,7 +20,7 @@ module ShortBus
|
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def match(item)
|
|
21
|
-
@specs.reduce(false) { |
|
|
23
|
+
@specs.reduce(false) { |a, e| a || match_single(e, item) }
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
private
|
|
@@ -38,8 +40,8 @@ module ShortBus
|
|
|
38
40
|
to_set ? [spec].to_set : spec
|
|
39
41
|
elsif spec.is_a? Set
|
|
40
42
|
spec.flatten
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
.map { |spec| process(spec, false) }
|
|
44
|
+
.to_set
|
|
43
45
|
elsif spec.is_a? String
|
|
44
46
|
to_set ? [string_to_regexp(spec)].to_set : string_to_regexp(spec)
|
|
45
47
|
elsif spec.is_a? NilClass
|
|
@@ -49,7 +51,7 @@ module ShortBus
|
|
|
49
51
|
|
|
50
52
|
def string_to_regexp(spec)
|
|
51
53
|
if spec.include? '*'
|
|
52
|
-
/^#{spec.gsub(/\*+/, '*' => '[
|
|
54
|
+
/^#{spec.gsub(/\*+/, '*' => '[^/]*', '**' => '.*')}/
|
|
53
55
|
else
|
|
54
56
|
spec
|
|
55
57
|
end
|
data/lib/short_bus/version.rb
CHANGED
data/lib/short_bus.rb
CHANGED
metadata
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: short_bus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rob Zwissler
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-06-
|
|
11
|
+
date: 2016-06-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - ~>
|
|
17
|
+
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '1.12'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - ~>
|
|
24
|
+
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.12'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - ~>
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '10.0'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - ~>
|
|
38
|
+
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '10.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rspec
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - ~>
|
|
45
|
+
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '3.0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - ~>
|
|
52
|
+
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '3.0'
|
|
55
55
|
description: Small, lightweight, easy to implement multi-threaded publish/subscribe
|
|
@@ -61,9 +61,9 @@ executables: []
|
|
|
61
61
|
extensions: []
|
|
62
62
|
extra_rdoc_files: []
|
|
63
63
|
files:
|
|
64
|
-
- .gitignore
|
|
65
|
-
- .rspec
|
|
66
|
-
- .travis.yml
|
|
64
|
+
- ".gitignore"
|
|
65
|
+
- ".rspec"
|
|
66
|
+
- ".travis.yml"
|
|
67
67
|
- Gemfile
|
|
68
68
|
- LICENSE.txt
|
|
69
69
|
- README.md
|
|
@@ -92,12 +92,12 @@ require_paths:
|
|
|
92
92
|
- lib
|
|
93
93
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
94
|
requirements:
|
|
95
|
-
- -
|
|
95
|
+
- - ">="
|
|
96
96
|
- !ruby/object:Gem::Version
|
|
97
97
|
version: '0'
|
|
98
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements:
|
|
100
|
-
- -
|
|
100
|
+
- - ">="
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
102
|
version: '0'
|
|
103
103
|
requirements: []
|
|
@@ -108,3 +108,4 @@ specification_version: 4
|
|
|
108
108
|
summary: Lightweight multi-threaded pub-sub message dispatcher for self-contained
|
|
109
109
|
service-oriented Ruby apps.
|
|
110
110
|
test_files: []
|
|
111
|
+
has_rdoc:
|