emissary 1.3.3 → 1.3.5
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.
- data/VERSION.yml +1 -1
- data/bin/amqp-listen +143 -0
- data/bin/emissary-send-message +154 -0
- metadata +9 -5
data/VERSION.yml
CHANGED
data/bin/amqp-listen
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'optparse'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
def require_lib library
|
9
|
+
begin
|
10
|
+
require library
|
11
|
+
rescue LoadError
|
12
|
+
real_name = library[/([^\/]+)/,1]
|
13
|
+
puts %Q(Missing required library '#{real_name}' - please install to continue: sudo gem install #{real_name})
|
14
|
+
exit! 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require_lib 'mq'
|
19
|
+
require_lib 'highline/import'
|
20
|
+
require_lib 'emissary'
|
21
|
+
|
22
|
+
$options = OpenStruct.new(
|
23
|
+
:user => 'nimbul',
|
24
|
+
:pass => nil,
|
25
|
+
:host => ENV['AMQP_HOST'] || 'mq.example.tld',
|
26
|
+
:port => ENV['AMQP_PORT'] || 5672,
|
27
|
+
:vhost => ENV['AMQP_VHOST'] || '/nimbul',
|
28
|
+
:ssl => (ENV['AMQP_USE_SSL'].nil? ? true : !!ENV['AMQP_USE_SSL']),
|
29
|
+
:bindings => { :direct => [], :topic => [], :fanout => [] }
|
30
|
+
)
|
31
|
+
|
32
|
+
def password
|
33
|
+
$options.pass = ask('Enter AMQP Service password: ') { |q| q.echo = '*' } unless not $options.pass.blank?
|
34
|
+
$options.pass
|
35
|
+
end
|
36
|
+
|
37
|
+
OptionParser.new("Usage: #{File.basename($0)} [options] -- 'exchange_type:route_key1' .. 'exchange_type:route_keyN' ") do |parser|
|
38
|
+
parser.separator ''
|
39
|
+
parser.separator "Connection Options:"
|
40
|
+
parser.on('-u', '--user [USER]', %Q(User to connect to the AMQP service as. Default: #{$options.user})) {|v| $options.user = v }
|
41
|
+
parser.on('-p', '--password [PASS]', %Q(Password to use when connecting to AMQP service. Default: <empty>)) { |v| $options.pass = escape_password(v)}
|
42
|
+
parser.on('-H', '--host [HOST]', String, %Q(Host to connect to for AMQP service. Default: #{$options.host})) {|v| $options.host= v }
|
43
|
+
parser.on('-P', '--port [PORT]', Integer, %Q(Port to connect to for AMQP service. Default: #{$options.port})) {|v| $options.port = v }
|
44
|
+
parser.on('-V', '--vhost [VHOST]', %Q(VHOST to use when connecting to AMQP service. Default: #{$options.vhost})) { |v| $options.vhost = v }
|
45
|
+
parser.on('--[no-]ssl', 'Use ssl (or not) when connecting to the AMQP service. Default: true') { |v| $options.ssl = !!v }
|
46
|
+
|
47
|
+
parser.separator ''
|
48
|
+
parser.separator 'General'
|
49
|
+
parser.on_tail('-h', '--help', 'This message') { puts parser.help; exit! 0 }
|
50
|
+
|
51
|
+
result = parser.parse!
|
52
|
+
|
53
|
+
unless ARGV.size > 0
|
54
|
+
puts "Missing required exchange bindings (format: <exchange>:<route_key>)"
|
55
|
+
exit! 1
|
56
|
+
else
|
57
|
+
ARGV.each do |binding|
|
58
|
+
binding = "topic:#{binding}" unless binding.include? ':'
|
59
|
+
type, route = binding.downcase.split(/:/)
|
60
|
+
|
61
|
+
unless $options.bindings.include? type.to_sym
|
62
|
+
puts %Q(Unsupported exchange type '#{type}' - valid exchanges are: #{$options.bindings.keys.join ', '})
|
63
|
+
exit! 1
|
64
|
+
end
|
65
|
+
|
66
|
+
$options.bindings[type.to_sym] << route
|
67
|
+
end
|
68
|
+
end
|
69
|
+
result
|
70
|
+
end
|
71
|
+
|
72
|
+
HOSTNAME = `hostname -f`.strip
|
73
|
+
|
74
|
+
def connect
|
75
|
+
@connect_details = {
|
76
|
+
:host => $options.host,
|
77
|
+
:ssl => $options.ssl,
|
78
|
+
:port => $options.port,
|
79
|
+
:user => $options.user,
|
80
|
+
:pass => password,
|
81
|
+
:vhost => $options.vhost
|
82
|
+
}
|
83
|
+
|
84
|
+
@connection = ::AMQP.connect(@connect_details)
|
85
|
+
@channel = ::MQ.new(@connection)
|
86
|
+
|
87
|
+
@queue_config = {
|
88
|
+
:durable => false,
|
89
|
+
:auto_delete => true,
|
90
|
+
:exclusive => true
|
91
|
+
}
|
92
|
+
|
93
|
+
puts "QUEUE: #{HOSTNAME}.#{$$}"
|
94
|
+
@queue = ::MQ::Queue.new(@channel, "#{HOSTNAME}.#{$$}", @queue_config)
|
95
|
+
|
96
|
+
@exchanges = {}
|
97
|
+
@exchanges[:topic] = ::MQ::Exchange.new(@channel, :topic, 'amq.topic')
|
98
|
+
@exchanges[:fanout] = ::MQ::Exchange.new(@channel, :fanout, 'amq.fanout')
|
99
|
+
@exchanges[:direct] = ::MQ::Exchange.new(@channel, :direct, 'amq.direct')
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def subscribe
|
104
|
+
$options.bindings.each do |type, bindings|
|
105
|
+
bindings.each { |routing_key|
|
106
|
+
puts "Binding to #{type.to_s.capitalize} exchange with routing key '#{routing_key}'"
|
107
|
+
@queue.bind(@exchanges[type], :key => routing_key )
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
puts; puts
|
112
|
+
puts "Waiting for Messages..."
|
113
|
+
puts "------"
|
114
|
+
|
115
|
+
@queue.subscribe do |header,message|
|
116
|
+
puts "Received Message:"
|
117
|
+
puts "------- START -------"
|
118
|
+
begin
|
119
|
+
m = Emissary::Message.decode(message)
|
120
|
+
puts
|
121
|
+
puts "AMQP Headers: #{header.inspect}"
|
122
|
+
puts "Emissary Headers: "; pp m.headers
|
123
|
+
puts "Emissary Data: "; pp m.data
|
124
|
+
puts "Emissary Errors: "; pp m.errors
|
125
|
+
rescue ::Emissary::Error::InvalidMessageFormat => e
|
126
|
+
puts
|
127
|
+
puts "AMQP Headers: #{header.inspect}"
|
128
|
+
puts "Message: #{message}"
|
129
|
+
end
|
130
|
+
puts "------- END -------"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
EM.run do
|
135
|
+
trap("INT") { EM.stop }
|
136
|
+
trap("TERM") { EM.stop }
|
137
|
+
connect
|
138
|
+
subscribe
|
139
|
+
EM.add_periodic_timer(300) {
|
140
|
+
# reset every five minutes in case of connection issues
|
141
|
+
@queue.reset
|
142
|
+
}
|
143
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
def require_lib library
|
7
|
+
begin
|
8
|
+
require library
|
9
|
+
rescue LoadError
|
10
|
+
puts %q(Missing required library '#{library[/([^\/]+)/,1}' - please install to continue: sudo gem install eventmachine)
|
11
|
+
exit! 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require_lib 'eventmachine'
|
16
|
+
require_lib 'highline/import'
|
17
|
+
require_lib 'emissary'
|
18
|
+
|
19
|
+
$options = OpenStruct.new(
|
20
|
+
:user => 'nimbul',
|
21
|
+
:pass => nil,
|
22
|
+
:host => ENV['AMQP_HOST'] || 'mq.example.tld',
|
23
|
+
:port => ENV['AMQP_PORT'] || 5672,
|
24
|
+
:vhost => ENV['AMQP_VHOST'] || '/nimbul',
|
25
|
+
:ssl => (ENV['AMQP_USE_SSL'].nil? ? true : !!ENV['AMQP_USE_SSL']),
|
26
|
+
:uri => '',
|
27
|
+
:route => 'request.#',
|
28
|
+
:exchange => 'topic',
|
29
|
+
:agent => :ping,
|
30
|
+
:func => :ping,
|
31
|
+
:account => -1,
|
32
|
+
:timeout => 0.25,
|
33
|
+
:show_message => false,
|
34
|
+
:raise_errors => true
|
35
|
+
)
|
36
|
+
|
37
|
+
$options.uri = "amqps://#{$options.host}:#{$options.port}/nimbul"
|
38
|
+
|
39
|
+
def escape_password password
|
40
|
+
URI.escape(password, '~`!@#$%^&*()_-+=[]{}|\:;<,>.?/')
|
41
|
+
end
|
42
|
+
|
43
|
+
OptionParser.new("Usage: #{File.basename($0)} [options] -- [ARGS]") do |parser|
|
44
|
+
parser.separator ''
|
45
|
+
parser.separator "Connection Options:"
|
46
|
+
|
47
|
+
parser.on('-u', '--user [USER]', %Q(User to connect to the AMQP service as. Default: #{$options.user})) {|v| $options.user = v }
|
48
|
+
parser.on('-p', '--password [PASS]', %Q(Password to use when connecting to AMQP service. Default: <empty>)) { |v| $options.pass = escape_password(v)}
|
49
|
+
parser.on('-H', '--host [HOST]', String, %Q(Host to connect to for AMQP service. Default: #{$options.host})) {|v| $options.host= v }
|
50
|
+
parser.on('-P', '--port [PORT]', Integer, %Q(Port to connect to for AMQP service. Default: #{$options.port})) {|v| $options.port = v }
|
51
|
+
parser.on('-V', '--vhost [VHOST]', %Q(VHOST to use when connecting to AMQP service. Default: #{$options.vhost})) { |v| $options.vhost = v }
|
52
|
+
parser.on('--[no-]ssl', 'Use ssl (or not) when connecting to the AMQP service. Default: true') { |v| $options.ssl = !!v }
|
53
|
+
parser.on('-U', '--uri [URI]', "URI to use when connecting. Default: #{$options.uri}") { |v| $options.uri = v }
|
54
|
+
|
55
|
+
parser.separator ''
|
56
|
+
parser.separator 'Routing Options:'
|
57
|
+
parser.on('-r', '--route [ROUTE]', String, 'Routing key to use when sending message') { |v| $options.route = v }
|
58
|
+
parser.on('-x', '--exchange [EXCHANGE]', [ 'topic', 'direct' ], 'Exchange type (topic/direct) used when routing message [DEFAULT: topic]') \
|
59
|
+
{ |v| $options.exchange = v.downcase }
|
60
|
+
|
61
|
+
parser.separator ''
|
62
|
+
parser.separator 'Package Data:'
|
63
|
+
parser.on('-a', '--agent [NAME]', String, 'Agent to request execution of') { |v| $options.agent = v.to_sym }
|
64
|
+
parser.on('-A', '--account [ID]', Integer, 'Account to request execution of') { |v| $options.account = v.to_i }
|
65
|
+
parser.on('-m', '--method [NAME]', String, 'Method to request execution of') { |v| $options.func = v.to_sym }
|
66
|
+
parser.on('-t', '--timeout [SECONDS]', Float, 'Time to wait from last message before quitting [DEFAULT: 5 seconds]') \
|
67
|
+
{ |v| v > 0 ? $options.timeout = v : nil }
|
68
|
+
|
69
|
+
parser.separator ''
|
70
|
+
parser.separator 'General'
|
71
|
+
parser.on_tail('--show-message', 'Display the message that would be sent and exit') { |v| $options.show_message = v }
|
72
|
+
parser.on_tail('--[no-]raise-errors', 'Raise errors received in respose messages.') { |v| $options.raise_errors = v }
|
73
|
+
parser.on_tail('-h', '--help', 'This message') { puts parser.help; exit! 0 }
|
74
|
+
|
75
|
+
result = parser.parse!
|
76
|
+
result
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_message
|
80
|
+
message = Emissary::Message.new(
|
81
|
+
:headers => {
|
82
|
+
:recipient => "#{$options.route}:#{$options.exchange}",
|
83
|
+
:replyto => 'nimbul:direct',
|
84
|
+
:sender => 'nimbul:direct',
|
85
|
+
:originator => 'nimbul:direct'
|
86
|
+
},
|
87
|
+
:data => {
|
88
|
+
:agent => $options.agent,
|
89
|
+
:method => $options.func,
|
90
|
+
:account => $options.account,
|
91
|
+
:args => ARGV
|
92
|
+
}
|
93
|
+
)
|
94
|
+
|
95
|
+
unless not $options.show_message
|
96
|
+
puts "Sending the following message:"; pp message
|
97
|
+
exit! 0
|
98
|
+
end
|
99
|
+
|
100
|
+
message
|
101
|
+
end
|
102
|
+
|
103
|
+
def get_operator
|
104
|
+
unless not $options.pass.blank?
|
105
|
+
$options.pass = escape_password(ask('Enter AMQP Service password: ') { |q| q.echo = '*' })
|
106
|
+
end
|
107
|
+
|
108
|
+
connect_uri = URI.parse($options.uri)
|
109
|
+
connect_uri.user = $options.user || 'nimbul'
|
110
|
+
connect_uri.password = $options.pass
|
111
|
+
connect_uri.host = $options.host
|
112
|
+
connect_uri.port = $options.port || ($options.ssl ? 5671 : 5672)
|
113
|
+
connect_uri.scheme = $options.ssl ? 'amqps' : 'amqp'
|
114
|
+
connect_uri.path = $options.vhost || '/'
|
115
|
+
|
116
|
+
puts "URI: #{connect_uri.to_s}"
|
117
|
+
operator = Emissary.call(:amqp, { :uri => connect_uri.to_s, :subscriptions => [] })
|
118
|
+
|
119
|
+
class << operator
|
120
|
+
alias :original_receive :receive
|
121
|
+
def last_received=(value) @last_received = value; end
|
122
|
+
def last_received() @last_received ||= Time.now; end
|
123
|
+
|
124
|
+
def receive message
|
125
|
+
last_received = Time.now
|
126
|
+
raise message.errors.first unless message.errors.empty? or not $options.raise_errors
|
127
|
+
$stdout.puts sprintf("Instance Response Recieved: %s - response time: %.2fms\n", message.replyto, (1000 * (last_received.to_f - @send_time.to_f)))
|
128
|
+
end
|
129
|
+
|
130
|
+
def send message
|
131
|
+
@send_time = Time.now
|
132
|
+
send_data message
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
operator
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
EM.run {
|
141
|
+
message = get_message
|
142
|
+
operator = get_operator
|
143
|
+
|
144
|
+
operator.connect
|
145
|
+
operator.subscribe
|
146
|
+
operator.send message
|
147
|
+
|
148
|
+
EM.add_periodic_timer(0.05) {
|
149
|
+
if Time.now.to_f - operator.last_received.to_f > $options.timeout.to_f
|
150
|
+
EM.stop
|
151
|
+
exit! 0
|
152
|
+
end
|
153
|
+
}
|
154
|
+
}
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: emissary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 5
|
10
|
+
version: 1.3.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Carl P. Corliss
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-09-09 00:00:00 -04:00
|
19
19
|
default_executable: bin/emissary-setup
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -181,8 +181,10 @@ dependencies:
|
|
181
181
|
description:
|
182
182
|
email: carl.corliss@nytimes.com
|
183
183
|
executables:
|
184
|
-
- emissary
|
185
184
|
- emissary-setup
|
185
|
+
- emissary-send-message
|
186
|
+
- emissary
|
187
|
+
- amqp-listen
|
186
188
|
extensions: []
|
187
189
|
|
188
190
|
extra_rdoc_files:
|
@@ -220,7 +222,9 @@ files:
|
|
220
222
|
- etc/init.d/emissary
|
221
223
|
- etc/emissary/config.ini
|
222
224
|
- bin/emissary-setup
|
225
|
+
- bin/emissary-send-message
|
223
226
|
- bin/emissary
|
227
|
+
- bin/amqp-listen
|
224
228
|
- VERSION.yml
|
225
229
|
- LICENSE
|
226
230
|
- README.txt
|