smith 0.7.9 → 0.8.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/bin/agency +1 -1
- data/config/smithrc.toml +5 -3
- data/lib/smith.rb +5 -4
- data/lib/smith/agent.rb +0 -2
- data/lib/smith/commands/agency/list.rb +6 -1
- data/lib/smith/commands/common.rb +3 -0
- data/lib/smith/config.rb +31 -1
- data/lib/smith/exceptions.rb +1 -0
- data/lib/smith/messaging/acl_type_cache.rb +74 -23
- data/lib/smith/messaging/receiver.rb +36 -5
- data/lib/smith/messaging/sender.rb +16 -8
- data/lib/smith/version.rb +1 -1
- metadata +17 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fd13c0ca6d5c956ef70e273ea19e61462eeb7f3
|
4
|
+
data.tar.gz: 84d57417643b928c8f82a4cb8f6e1a502276fbb5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c901e07b496c3ae7e1b1c9daf15a0be08364d2fd8b3c3fdde81b7d99729317c6baff917d09cef73917c45ce4371a2085c8015eb4b9e8a7d3614bfb8eae1af5fb
|
7
|
+
data.tar.gz: 1aeb3abe83daa143aea4af316fc0d3646f175d1fc586ce3b78318332a073193996b04c297a66aec4fa10f56748f06241f24a9d49d7e7183e8e57ed46c125218d
|
data/bin/agency
CHANGED
@@ -78,7 +78,7 @@ module Smith
|
|
78
78
|
|
79
79
|
def add_vhost(name)
|
80
80
|
suffix = Pathname.new(Smith.config.amqp.broker.vhost).basename
|
81
|
-
"%s.%s" % [name, (suffix.root?) ? '
|
81
|
+
"%s.%s" % [name, (suffix.to_s.empty? || suffix.root?) ? 'default' : suffix.to_s]
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
data/config/smithrc.toml
CHANGED
@@ -48,9 +48,11 @@ ack = true
|
|
48
48
|
[amqp.broker]
|
49
49
|
host = "localhost"
|
50
50
|
port = 5672
|
51
|
-
user = "
|
52
|
-
password = "
|
53
|
-
vhost = "
|
51
|
+
user = "smith"
|
52
|
+
password = "smith"
|
53
|
+
vhost = "smith"
|
54
|
+
|
55
|
+
# uri = "amqp://smith:smith@basking:5672/smith"
|
54
56
|
|
55
57
|
[logging]
|
56
58
|
trace = true
|
data/lib/smith.rb
CHANGED
@@ -90,11 +90,12 @@ module Smith
|
|
90
90
|
EM.kqueue
|
91
91
|
end
|
92
92
|
|
93
|
-
connection_settings =
|
93
|
+
connection_settings = {
|
94
94
|
:on_tcp_connection_failure => method(:tcp_connection_failure_handler),
|
95
|
-
:on_possible_authentication_failure => method(:authentication_failure_handler)
|
95
|
+
:on_possible_authentication_failure => method(:authentication_failure_handler)
|
96
|
+
}
|
96
97
|
|
97
|
-
AMQP.start(connection_settings) do |connection|
|
98
|
+
AMQP.start(config.amqp.broker.uri.to_s, connection_settings) do |connection|
|
98
99
|
@connection = connection
|
99
100
|
|
100
101
|
connection.on_connection do
|
@@ -181,7 +182,7 @@ module Smith
|
|
181
182
|
|
182
183
|
def broker_identifier(connection)
|
183
184
|
broker = connection.broker.properties
|
184
|
-
"
|
185
|
+
"amqp://#{connection.broker_endpoint}, (#{broker['product']}/v#{broker['version']}, #{broker['cluster_name']})"
|
185
186
|
end
|
186
187
|
|
187
188
|
def check_path(path, create=false)
|
data/lib/smith/agent.rb
CHANGED
@@ -18,7 +18,12 @@ module Smith
|
|
18
18
|
(a.empty?) ? AgentProcess.new(nil, :name => agent_name, :uuid => nil_uuid) : a.first
|
19
19
|
end
|
20
20
|
when options[:group]
|
21
|
-
|
21
|
+
begin
|
22
|
+
selected_agents = agents.find_by_name(agent_group(options[:group]))
|
23
|
+
rescue RuntimeError => e
|
24
|
+
responder.fail(e.message)
|
25
|
+
return
|
26
|
+
end
|
22
27
|
else
|
23
28
|
selected_agents = (options[:all]) ? agents.to_a : agents.state(:running)
|
24
29
|
end
|
@@ -13,6 +13,9 @@ module Smith
|
|
13
13
|
# @return [Array<Class>] the class of each agent in the group
|
14
14
|
def agent_group(group)
|
15
15
|
agents = Smith.agent_directories.map do |agent_directory|
|
16
|
+
|
17
|
+
raise RuntimeError, "No group specified." unless group
|
18
|
+
|
16
19
|
group_directory(agent_directory, group) do |group_directory, groups_prefix|
|
17
20
|
|
18
21
|
if group_directory.exist? && group_directory.directory?
|
data/lib/smith/config.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
require 'toml'
|
5
5
|
require 'fileutils'
|
6
6
|
require 'pathname'
|
7
|
+
require 'addressable/uri'
|
7
8
|
require 'hashie/extensions/coercion'
|
8
9
|
require 'hashie/extensions/deep_merge'
|
9
10
|
require 'hashie/extensions/method_access'
|
@@ -53,6 +54,7 @@ module Smith
|
|
53
54
|
@config_file = find_config_file
|
54
55
|
@config = load_tomls(default_config_file, @config_file)
|
55
56
|
coerce_directories!
|
57
|
+
broker_uri!
|
56
58
|
end
|
57
59
|
|
58
60
|
# Make sure the non-default direcotires are set.
|
@@ -81,6 +83,24 @@ module Smith
|
|
81
83
|
@config.agency[:acl_directories] = @config.agency[:acl_directories] + [smith_acl_directory]
|
82
84
|
end
|
83
85
|
|
86
|
+
def broker_uri!
|
87
|
+
uri = if @config.amqp.broker[:uri]
|
88
|
+
Addressable::URI.parse(@config.amqp.broker[:uri])
|
89
|
+
else
|
90
|
+
Addressable::URI.new.tap do |u|
|
91
|
+
u.scheme = 'amqp'
|
92
|
+
u.host = @config.amqp.broker.delete(:host)
|
93
|
+
u.port = @config.amqp.broker.delete(:port)
|
94
|
+
u.path = @config.amqp.broker.delete(:vhost)
|
95
|
+
u.user = @config.amqp.broker.delete(:user)
|
96
|
+
u.password = @config.amqp.broker.delete(:password)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
@config.amqp.broker[:uri] = uri_from_env('SMITH_BROKER_URI', uri)
|
101
|
+
@config.amqp.broker[:vhost] = @config.amqp.broker[:uri].path
|
102
|
+
end
|
103
|
+
|
84
104
|
# Find the config file. This checks the following paths before raising an
|
85
105
|
# exception:
|
86
106
|
#
|
@@ -122,7 +142,7 @@ module Smith
|
|
122
142
|
to_pathname(ENV.fetch(env_var, default))
|
123
143
|
end
|
124
144
|
|
125
|
-
# Returns an array of
|
145
|
+
# Returns an array of Paths from the environment variable passed in. If the
|
126
146
|
# environment variable is not set it returns an empty array.
|
127
147
|
#
|
128
148
|
# @param env_var [String] the name of the environment variable
|
@@ -132,6 +152,16 @@ module Smith
|
|
132
152
|
split_paths(ENV.fetch(env_var, default))
|
133
153
|
end
|
134
154
|
|
155
|
+
# Returns a URI from the environment variable passed in. If the
|
156
|
+
# environment variable is not set it returns nil.
|
157
|
+
#
|
158
|
+
# @param env_var [String] the name of the environment variable
|
159
|
+
# @param default [String] the value to use if the environment variable is not set
|
160
|
+
# @return [Addressable::URI]
|
161
|
+
def uri_from_env(env_var, default)
|
162
|
+
Addressable::URI.parse(ENV.fetch(env_var, default))
|
163
|
+
end
|
164
|
+
|
135
165
|
# Splits a string using PATH_SEPARATOR.
|
136
166
|
#
|
137
167
|
# @param paths to split
|
data/lib/smith/exceptions.rb
CHANGED
@@ -10,68 +10,119 @@ module Smith
|
|
10
10
|
include Singleton
|
11
11
|
include MurmurHash3
|
12
12
|
|
13
|
+
SUPPORTED_FORMATS = [:string, :binary]
|
14
|
+
DEFAULT_FORMAT = :string
|
15
|
+
|
13
16
|
def initialize
|
14
17
|
clear!
|
15
18
|
end
|
16
19
|
|
20
|
+
# Add the type to the cashe. This will add the type for all know formats
|
21
|
+
# @param type [Class] the type to add
|
22
|
+
# @return [true|false] true if the type was added or false if it already exists.
|
17
23
|
def add(type)
|
18
|
-
if @types[type
|
24
|
+
if SUPPORTED_FORMATS.all? { |format| @types[format].has_key?(type) }
|
19
25
|
false
|
20
26
|
else
|
21
|
-
|
22
|
-
|
23
|
-
|
27
|
+
SUPPORTED_FORMATS.each do |format|
|
28
|
+
h = to_murmur32(type, format)
|
29
|
+
@types[format][type] = h
|
30
|
+
@hashes[format][h] = type
|
31
|
+
end
|
32
|
+
|
24
33
|
@legacy_types_by_hash[type.to_s.split(/::/)[-1].snake_case] = type
|
25
34
|
true
|
26
35
|
end
|
27
36
|
end
|
28
37
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
38
|
+
# Return the type given the mumur3 hash
|
39
|
+
# @param type [Sting] the mumur3 hash to lookup
|
40
|
+
# @param format [Symbol] the format of the mumor3 hash. Defaults to
|
41
|
+
# Smith::AclTypeCache::DEFAULT_FORMAT
|
42
|
+
# @return [Class]
|
43
|
+
# @raise [Smith::ACL::UnknownError] raised when an unknown ACL is given
|
44
|
+
def get_by_hash(type, format=DEFAULT_FORMAT)
|
45
|
+
if t = dump_hashes(format)[type]
|
46
|
+
t
|
47
|
+
else
|
48
|
+
if t = @legacy_types_by_hash[type.to_s]
|
49
|
+
t
|
50
|
+
else
|
51
|
+
raise ACL::UnknownError, "Unknown ACL: #{t}"
|
52
|
+
end
|
34
53
|
end
|
35
54
|
end
|
36
55
|
|
37
|
-
|
38
|
-
|
56
|
+
# Return the mumur3 hash of the given the type
|
57
|
+
# @param type [Class] the class to lookup
|
58
|
+
# @param format [Symbol] the format of the mumor3 hash. Defaults to
|
59
|
+
# Smith::AclTypeCache::DEFAULT_FORMAT
|
60
|
+
# @return [String]
|
61
|
+
def get_by_type(type, format=DEFAULT_FORMAT)
|
62
|
+
dump_types(format)[type].tap { |t| raise ACL::UnknownError, "Unknown ACL: #{t}" if type.nil? }
|
39
63
|
end
|
40
64
|
|
41
65
|
# Look the key up in the cache. This defaults to the key being the hash.
|
42
66
|
# If :by_type => true is passed in as the second argument then it will
|
43
67
|
# perform the lookup in the type hash.
|
44
|
-
#
|
45
68
|
def include?(key, opts={})
|
46
69
|
if opts[:by_type]
|
47
|
-
!get_by_type(key).nil?
|
70
|
+
!get_by_type(key, opts.fetch(:format, DEFAULT_FORMAT)).nil?
|
48
71
|
else
|
49
|
-
!get_by_hash(key).nil?
|
72
|
+
!get_by_hash(key, opts.fetch(:format, DEFAULT_FORMAT)).nil?
|
50
73
|
end
|
51
74
|
end
|
52
75
|
|
53
76
|
# Clear the internal hashes.
|
54
77
|
def clear!
|
55
|
-
@types = {}
|
56
|
-
@hashes = {}
|
78
|
+
@types = SUPPORTED_FORMATS.each_with_object({}) { |v, acc| acc[v] = {} }
|
79
|
+
@hashes = SUPPORTED_FORMATS.each_with_object({}) { |v, acc| acc[v] = {} }
|
57
80
|
@legacy_types_by_hash = {}
|
58
81
|
end
|
59
82
|
|
60
83
|
# Dump the type hash
|
61
|
-
|
62
|
-
|
84
|
+
# @param format [Symbol] the format of the mumor3 hash. Defaults to
|
85
|
+
# Smith::AclTypeCache::DEFAULT_FORMAT
|
86
|
+
# @return [Hash]
|
87
|
+
# @raise [Smith::ACL::UnknownTypeFormat] raised when an unknown format is given
|
88
|
+
def dump_types(format=DEFAULT_FORMAT)
|
89
|
+
if @types.has_key?(format)
|
90
|
+
@types[format]
|
91
|
+
else
|
92
|
+
raise ACL::UnknownTypeFormat, "Uknown format: #{format}"
|
93
|
+
end
|
63
94
|
end
|
64
95
|
|
65
96
|
# Dump the hashes hash
|
66
|
-
|
67
|
-
|
97
|
+
# @param format [Symbol] the format of the mumor3 hash. Defaults to
|
98
|
+
# Smith::AclTypeCache::DEFAULT_FORMAT
|
99
|
+
# @return [Hash]
|
100
|
+
# @raise [Smith::ACL::UnknownTypeFormat] raised when an unknown format is given
|
101
|
+
def dump_hashes(format=DEFAULT_FORMAT)
|
102
|
+
if @hashes.has_key?(format)
|
103
|
+
@hashes[format]
|
104
|
+
else
|
105
|
+
raise ACL::UnknownTypeFormat, "Uknown format: #{format}"
|
106
|
+
end
|
68
107
|
end
|
69
108
|
|
70
109
|
private
|
71
110
|
|
72
|
-
# Convert the
|
73
|
-
|
74
|
-
|
111
|
+
# Convert the type to a murmor3 hash
|
112
|
+
# @param type [Class] the class to lookup
|
113
|
+
# @param format [Symbol] the format of the mumor3 hash. Defaults to
|
114
|
+
# Smith::AclTypeCache::DEFAULT_FORMAT
|
115
|
+
# @return [String]
|
116
|
+
# @raise [Smith::ACL::UnknownTypeFormat] raised when an unknown format is given
|
117
|
+
def to_murmur32(type, format)
|
118
|
+
case format
|
119
|
+
when :string
|
120
|
+
MurmurHash3::V32.murmur3_32_str_hash(type.to_s).to_s(36)
|
121
|
+
when :binary
|
122
|
+
MurmurHash3::V32.murmur3_32_str_hash(type.to_s)
|
123
|
+
else
|
124
|
+
raise ACL::UnknownTypeFormat, "Uknown format: #{format}"
|
125
|
+
end
|
75
126
|
end
|
76
127
|
end
|
77
128
|
end
|
@@ -21,6 +21,10 @@ module Smith
|
|
21
21
|
:auto_ack => option_or_default(@queue_def.options, :auto_ack, true),
|
22
22
|
:threading => option_or_default(@queue_def.options, :threading, false)}
|
23
23
|
|
24
|
+
fanout_options = if opts.delete(:fanout)
|
25
|
+
{:persistence => opts.delete(:fanout_persistence) { true }, :queue_suffix => opts.delete(:fanout_queue_suffix)}
|
26
|
+
end
|
27
|
+
|
24
28
|
@payload_type = Array(option_or_default(@queue_def.options, :type, []))
|
25
29
|
|
26
30
|
prefetch = option_or_default(@queue_def.options, :prefetch, Smith.config.agent.prefetch)
|
@@ -39,13 +43,14 @@ module Smith
|
|
39
43
|
|
40
44
|
open_channel(:prefetch => prefetch) do |channel|
|
41
45
|
@channel_completion.succeed(channel)
|
42
|
-
|
46
|
+
exchange_type = (fanout_options) ? :fanout : :direct
|
47
|
+
channel.send(exchange_type, @queue_def.normalise, @options.exchange) do |exchange|
|
43
48
|
@exchange_completion.succeed(exchange)
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
47
52
|
open_channel(:prefetch => prefetch) do |channel|
|
48
|
-
channel.queue(
|
53
|
+
channel.queue(*fanout_queue_and_opts(fanout_options)) do |queue|
|
49
54
|
@exchange_completion.completion do |exchange|
|
50
55
|
queue.bind(exchange, :routing_key => @queue_def.normalise)
|
51
56
|
@queue_completion.succeed(queue)
|
@@ -68,9 +73,9 @@ module Smith
|
|
68
73
|
@exchange_completion.completion do |exchange|
|
69
74
|
logger.debug { "Attaching to reply queue: #{reply_queue_name}" }
|
70
75
|
|
71
|
-
|
76
|
+
reply_queue_def = QueueDefinition.new(reply_queue_name, :auto_delete => true, :immediate => true, :mandatory => true, :durable => false)
|
72
77
|
|
73
|
-
Smith::Messaging::Sender.new(
|
78
|
+
Smith::Messaging::Sender.new(reply_queue_def) do |sender|
|
74
79
|
@reply_queues[reply_queue_name] = sender
|
75
80
|
blk.call(sender)
|
76
81
|
end
|
@@ -200,6 +205,33 @@ module Smith
|
|
200
205
|
requeue_options.merge!(:on_requeue_limit => blk)
|
201
206
|
end
|
202
207
|
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
# Calculates the queue name and the various queue options based on the
|
212
|
+
# fanout_options and returns them in a form that can be used by the
|
213
|
+
# queue constuctor.
|
214
|
+
#
|
215
|
+
# @param [Hash] fanout_options the various fanout related options
|
216
|
+
#
|
217
|
+
# @raise [ArgumentError] raised if :queue_suffix is given without the :persistence flag
|
218
|
+
#
|
219
|
+
# @return [Array<queue_name, options]
|
220
|
+
def fanout_queue_and_opts(fanout_options)
|
221
|
+
if fanout_options
|
222
|
+
if fanout_options[:persistence]
|
223
|
+
if fanout_options[:queue_suffix]
|
224
|
+
["#{@queue_def.normalise}.#{fanout_options[:queue_suffix]}", @options.queue]
|
225
|
+
else
|
226
|
+
raise ArgumentError, "Incorrect options. :fanout_queue_suffix must be provided if :fanout_persistence is true."
|
227
|
+
end
|
228
|
+
else
|
229
|
+
["", @options.queue.merge(:durable => false, :auto_delete => true)]
|
230
|
+
end
|
231
|
+
else
|
232
|
+
[@queue_def.normalise, @options.queue]
|
233
|
+
end
|
234
|
+
end
|
203
235
|
end
|
204
236
|
|
205
237
|
class Foo
|
@@ -218,7 +250,6 @@ module Smith
|
|
218
250
|
|
219
251
|
# TODO add some better error checking/diagnostics.
|
220
252
|
clazz = @acl_type_cache.get_by_hash(metadata.type)
|
221
|
-
raise ACL::UnknownError, "Unknown ACL: #{metadata.type}" if clazz.nil?
|
222
253
|
|
223
254
|
@message = clazz.new.parse_from_string(data)
|
224
255
|
|
@@ -29,18 +29,26 @@ module Smith
|
|
29
29
|
|
30
30
|
open_channel(:prefetch => prefetch) do |channel|
|
31
31
|
@channel_completion.succeed(channel)
|
32
|
-
|
32
|
+
exchange_type = (opts[:fanout]) ? :fanout : :direct
|
33
33
|
|
34
|
-
|
35
|
-
logger.error { "#{@acl_type_cache[metadata.type].new.parse_from_string} returned! Exchange: #{reply_code.exchange}, reply_code: #{basic_return.reply_code}, reply_text: #{basic_return.reply_text}" }
|
36
|
-
logger.error { "Properties: #{metadata.properties}" }
|
37
|
-
end
|
34
|
+
channel.send(exchange_type, @queue_def.normalise, @options.exchange) do |exchange|
|
38
35
|
|
39
|
-
|
40
|
-
|
36
|
+
exchange.on_return do |basic_return, metadata, payload|
|
37
|
+
logger.error {
|
38
|
+
acl_type = @acl_type_cache.get_by_hash(metadata.properties[:type]).to_s rescue "Unknown ACL type"
|
39
|
+
"Cannot deliver message type: #{acl_type}, from exchange: \"#{basic_return.exchange}\", using routing key: \"#{basic_return.routing_key}\""
|
40
|
+
}
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
+
if opts[:fanout]
|
43
44
|
@exchange_completion.succeed(exchange)
|
45
|
+
else
|
46
|
+
channel.queue(@queue_def.normalise, @options.queue) do |queue|
|
47
|
+
queue.bind(exchange, :routing_key => @queue_def.normalise)
|
48
|
+
|
49
|
+
@queue_completion.succeed(queue)
|
50
|
+
@exchange_completion.succeed(exchange)
|
51
|
+
end
|
44
52
|
end
|
45
53
|
end
|
46
54
|
end
|
data/lib/smith/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smith
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Heycock
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: amqp
|
@@ -30,6 +30,20 @@ dependencies:
|
|
30
30
|
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '1.5'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: addressable
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '2.0'
|
33
47
|
- !ruby/object:Gem::Dependency
|
34
48
|
name: daemons
|
35
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -346,9 +360,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
346
360
|
version: '0'
|
347
361
|
requirements: []
|
348
362
|
rubyforge_project: smith
|
349
|
-
rubygems_version: 2.
|
363
|
+
rubygems_version: 2.5.1
|
350
364
|
signing_key:
|
351
365
|
specification_version: 4
|
352
366
|
summary: Multi-agent framework
|
353
367
|
test_files: []
|
354
|
-
has_rdoc:
|