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 CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
3
  :minor: 3
4
- :patch: 3
4
+ :patch: 5
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: 29
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 3
10
- version: 1.3.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-08-19 00:00:00 -04:00
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