openwferu 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/examples/mano_tracker.rb +11 -13
  2. data/lib/openwfe.rb +2 -4
  3. data/lib/openwfe/contextual.rb +8 -2
  4. data/lib/openwfe/engine/engine.rb +118 -2
  5. data/lib/openwfe/expool/expressionpool.rb +148 -53
  6. data/lib/openwfe/expool/expstorage.rb +36 -4
  7. data/lib/openwfe/expool/yamlexpstorage.rb +18 -0
  8. data/lib/openwfe/expressions/environment.rb +1 -1
  9. data/lib/openwfe/expressions/fe_misc.rb +14 -2
  10. data/lib/openwfe/expressions/fe_raw.rb +27 -11
  11. data/lib/openwfe/expressions/fe_subprocess.rb +45 -12
  12. data/lib/openwfe/expressions/fe_utils.rb +1 -1
  13. data/lib/openwfe/expressions/flowexpression.rb +5 -1
  14. data/lib/openwfe/expressions/raw_prog.rb +80 -32
  15. data/lib/openwfe/expressions/raw_xml.rb +10 -0
  16. data/lib/openwfe/flowexpressionid.rb +28 -7
  17. data/lib/openwfe/listeners/listener.rb +106 -0
  18. data/lib/openwfe/listeners/listeners.rb +140 -0
  19. data/lib/openwfe/listeners/socketlisteners.rb +239 -0
  20. data/lib/openwfe/listeners/sqslisteners.rb +145 -0
  21. data/lib/openwfe/participants/{csvparticipant.rb → csvparticipants.rb} +0 -0
  22. data/lib/openwfe/participants/{enoparticipant.rb → enoparticipants.rb} +1 -1
  23. data/lib/openwfe/participants/participantmap.rb +33 -1
  24. data/lib/openwfe/participants/participants.rb +99 -11
  25. data/lib/openwfe/participants/soapparticipants.rb +28 -8
  26. data/lib/openwfe/participants/socketparticipants.rb +172 -0
  27. data/lib/openwfe/participants/sqsparticipants.rb +121 -0
  28. data/lib/openwfe/rest/definitions.rb +1 -1
  29. data/lib/openwfe/{osocket.rb → rest/osocket.rb} +16 -8
  30. data/lib/openwfe/rest/xmlcodec.rb +41 -5
  31. data/lib/openwfe/storage/yamlfilestorage.rb +10 -13
  32. data/lib/openwfe/util/dollar.rb +23 -2
  33. data/lib/openwfe/util/otime.rb +1 -1
  34. data/lib/openwfe/util/safe.rb +149 -0
  35. data/lib/openwfe/util/scheduler.rb +47 -5
  36. data/lib/openwfe/util/sqs.rb +582 -0
  37. data/lib/openwfe/utils.rb +23 -0
  38. data/lib/openwfe/version.rb +1 -1
  39. data/lib/openwfe/workitem.rb +86 -3
  40. data/lib/openwfe/worklist/storeparticipant.rb +44 -4
  41. data/test/csv_test.rb +1 -1
  42. data/test/eno_test.rb +1 -1
  43. data/test/fei_test.rb +2 -15
  44. data/test/flowtestbase.rb +6 -2
  45. data/test/ft_11_ppd.rb +31 -0
  46. data/test/ft_13_eno.rb +1 -1
  47. data/test/ft_14b_subprocess.rb +74 -0
  48. data/test/ft_15_iterator.rb +0 -1
  49. data/test/ft_19_csv.rb +1 -1
  50. data/test/ft_20_cron.rb +1 -1
  51. data/test/ft_21_cron.rb +1 -1
  52. data/test/ft_27_getflowpos.rb +89 -0
  53. data/test/ft_28_fileparticipant.rb +65 -0
  54. data/test/ft_29_httprb.rb +95 -0
  55. data/test/ft_30_socketlistener.rb +197 -0
  56. data/test/ft_4_misc.rb +2 -1
  57. data/test/hash_test.rb +75 -0
  58. data/test/rake_qtest.rb +5 -4
  59. data/test/raw_prog_test.rb +205 -0
  60. data/test/rutest_utils.rb +16 -0
  61. data/test/safely_test.rb +89 -0
  62. data/test/scheduler_test.rb +71 -0
  63. data/test/sqs_test.rb +103 -0
  64. metadata +21 -6
  65. data/test/journal_persistence_test.rb +0 -147
@@ -194,16 +194,38 @@ module OpenWFE
194
194
  #
195
195
  def schedule_in (duration, schedulable=nil, params=nil, &block)
196
196
 
197
- if duration.kind_of?(String)
198
- duration = OpenWFE::parse_time_string(duration)
199
- elsif not duration.kind_of?(Float)
200
- duration = Float(duration.to_s)
201
- end
197
+ duration = duration_to_f(duration)
202
198
 
203
199
  return schedule_at(
204
200
  Time.new.to_f + duration, schedulable, params, &block)
205
201
  end
206
202
 
203
+ #
204
+ # Schedules a job in a loop. After an execution, it will not execute
205
+ # before the time specified in 'freq'.
206
+ #
207
+ # Note that if your job takes 2s to execute and the freq is set to
208
+ # 10s, it will in fact execute every 12s.
209
+ #
210
+ def schedule_every (freq, schedulable=nil, params=nil, &block)
211
+
212
+ f = duration_to_f(freq)
213
+
214
+ job_id = schedule_in(f) do |eid, at|
215
+ if schedulable
216
+ schedulable.trigger(params)
217
+ else
218
+ block.call eid, at
219
+ end
220
+ schedule_every(f, schedulable, params, &block)
221
+ end
222
+
223
+ schedulable.job_id = job_id \
224
+ if schedulable and schedulable.respond_to? :job_id=
225
+
226
+ job_id
227
+ end
228
+
207
229
  #
208
230
  # Unschedules an 'at' or a 'cron' job identified by the id
209
231
  # it was given at schedule time.
@@ -317,8 +339,28 @@ module OpenWFE
317
339
  @cron_entries.size
318
340
  end
319
341
 
342
+ #
343
+ # Returns true if the given string seems to be a cron string.
344
+ #
345
+ def Scheduler.is_cron_string (s)
346
+ return s.match(".+ .+ .+ .+ .+")
347
+ end
348
+
320
349
  protected
321
350
 
351
+ #
352
+ # Ensures that a duration is a expressed as a Float instance.
353
+ #
354
+ # duration_to_f("10s")
355
+ #
356
+ # will yields 10.0
357
+ #
358
+ def duration_to_f (s)
359
+ return s if s.kind_of? Float
360
+ return OpenWFE::parse_time_string(s) if s.kind_of? String
361
+ return Float(s.to_s)
362
+ end
363
+
322
364
  def to_block (schedulable, params, &block)
323
365
  if schedulable
324
366
  lambda do
@@ -0,0 +1,582 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2007, John Mettraux, OpenWFE.org
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # . Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # . Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
17
+ # used to endorse or promote products derived from this software without
18
+ # specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #++
32
+ #
33
+ # $Id$
34
+ #
35
+
36
+ #
37
+ # Made in Japan
38
+ #
39
+ # John dot Mettraux at OpenWFE dot org
40
+ #
41
+
42
+ require 'base64'
43
+ require 'cgi'
44
+ require 'net/https'
45
+ require 'rexml/document'
46
+ require 'time'
47
+ #require 'digest/md5'
48
+ require 'pp'
49
+
50
+
51
+ module SQS
52
+
53
+ #
54
+ # An SQS message (after its creation).
55
+ #
56
+ class Message
57
+
58
+ attr_reader :queue, :message_id, :message_body
59
+
60
+ def initialize (queue, xml_element)
61
+
62
+ @queue = queue
63
+ @message_id = SQS::get_element_text(xml_element, "MessageId")
64
+ @message_body = SQS::get_element_text(xml_element, "MessageBody")
65
+ end
66
+
67
+ #
68
+ # Connects to the queue service and deletes this message in its queue.
69
+ #
70
+ def delete
71
+ @queue.queue_service.delete_message(@queue, @message_id)
72
+ end
73
+ end
74
+
75
+ #
76
+ # An SQS queue (gathering all the necessary info about it
77
+ # in a single class).
78
+ #
79
+ class Queue
80
+
81
+ attr_reader :queue_service, :host, :path, :name
82
+
83
+ def initialize (queue_service, xml_element)
84
+
85
+ @queue_service = queue_service
86
+
87
+ s = xml_element.text.to_s
88
+ m = Regexp.compile('^http://(.*)(/.*)(/.*$)').match(s)
89
+ @host = m[1]
90
+ @name = m[3][1..-1]
91
+ @path = m[2] + m[3]
92
+ end
93
+ end
94
+
95
+ class QueueService
96
+
97
+ AWS_VERSION = "2006-04-01"
98
+ DEFAULT_QUEUE_HOST = "queue.amazonaws.com"
99
+
100
+ def initialize (queue_host=nil)
101
+
102
+ @queue_host = queue_host
103
+ @queue_host = DEFAULT_QUEUE_HOST unless @queue_host
104
+ end
105
+
106
+ #
107
+ # Lists the queues for the active AWS account.
108
+ # If 'prefix' is given, only queues whose name begin with that
109
+ # prefix will be returned.
110
+ #
111
+ def list_queues (prefix=nil)
112
+
113
+ queues = []
114
+
115
+ path = "/"
116
+ path = "#{path}?QueueNamePrefix=#{prefix}" if prefix
117
+
118
+ doc = do_action :get, @queue_host, path
119
+
120
+ doc.elements.each("//QueueUrl") do |e|
121
+ queues << Queue.new(self, e)
122
+ end
123
+
124
+ return queues
125
+ end
126
+
127
+ #
128
+ # Creates a queue.
129
+ #
130
+ # If the queue name doesn't comply with SQS requirements for it,
131
+ # an error will be raised.
132
+ #
133
+ def create_queue (queue_name)
134
+
135
+ doc = do_action :post, @queue_host, "/?QueueName=#{queue_name}"
136
+
137
+ doc.elements.each("//QueueUrl") do |e|
138
+ return e.text.to_s
139
+ end
140
+ end
141
+
142
+ #
143
+ # Given some content ('text/plain' content), send it as a message to
144
+ # a queue.
145
+ # Returns the SQS message id (a String).
146
+ #
147
+ # The queue might be a queue name (String) or a Queue instance.
148
+ #
149
+ def put_message (queue, content)
150
+
151
+ queue = resolve_queue(queue)
152
+
153
+ doc = do_action :put, queue.host, "#{queue.path}/back", content
154
+
155
+ #puts doc.to_s
156
+
157
+ #status_code = SQS::get_element_text(doc, '//StatusCode')
158
+ #message_id = SQS::get_element_text(doc, '//MessageId')
159
+ #request_id = SQS::get_element_text(doc, '//RequestId')
160
+ #{ :status_code => status_code,
161
+ # :message_id => message_id,
162
+ # :request_id => request_id }
163
+
164
+ SQS::get_element_text(doc, '//MessageId')
165
+ end
166
+
167
+ alias :send_message :put_message
168
+
169
+ #
170
+ # Retrieves a bunch of messages from a queue. Returns a list of
171
+ # Message instances.
172
+ #
173
+ # There are actually two optional params that this method understands :
174
+ #
175
+ # - :timeout the duration in seconds of the message visibility in the
176
+ # queue
177
+ # - :count the max number of message to be returned by this call
178
+ #
179
+ # The queue might be a queue name (String) or a Queue instance.
180
+ #
181
+ def get_messages (queue, params={})
182
+
183
+ queue = resolve_queue(queue)
184
+
185
+ path = "#{queue.path}/front"
186
+
187
+ path += "?" if params.size > 0
188
+
189
+ timeout = params[:timeout]
190
+ count = params[:count]
191
+
192
+ path += "VisibilityTimeout=#{timeout}" if timeout
193
+ path += "&" if timeout and count
194
+ path += "NumberOfMessages=#{count}" if count
195
+
196
+ doc = do_action :get, queue.host, path
197
+
198
+ messages = []
199
+
200
+ doc.elements.each("//Message") do |me|
201
+ messages << Message.new(queue, me)
202
+ end
203
+
204
+ messages
205
+ end
206
+
207
+ #
208
+ # Retrieves a single message from a queue. Returns an instance of
209
+ # Message.
210
+ #
211
+ # The queue might be a queue name (String) or a Queue instance.
212
+ #
213
+ def get_message (queue, message_id)
214
+
215
+ queue = resolve_queue(queue)
216
+
217
+ path = "#{queue.path}/#{message_id}"
218
+
219
+ begin
220
+ doc = do_action :get, queue.host, path
221
+ Message.new(queue, doc.root.elements[1])
222
+ rescue Exception => e
223
+ #puts e.message
224
+ return nil if e.message.match "^404 .*$"
225
+ raise e
226
+ end
227
+ end
228
+
229
+ #
230
+ # Deletes a given message.
231
+ #
232
+ # The queue might be a queue name (String) or a Queue instance.
233
+ #
234
+ def delete_message (queue, message_id)
235
+
236
+ queue = resolve_queue(queue)
237
+
238
+ path = "#{queue.path}/#{message_id}"
239
+ #path = "#{queue.path}/#{CGI::escape(message_id)}"
240
+
241
+ doc = do_action :delete, queue.host, path
242
+
243
+ SQS::get_element_text(doc, "//StatusCode") == "Success"
244
+ end
245
+
246
+ #
247
+ # Use with care !
248
+ #
249
+ # Attempts at deleting all the messages in a queue.
250
+ # Returns the total count of messages deleted.
251
+ #
252
+ # A call on this method might take a certain time, as it has
253
+ # to delete each message individually. AWS will perhaps
254
+ # add a proper 'flush_queue' method later.
255
+ #
256
+ # The queue might be a queue name (String) or a Queue instance.
257
+ #
258
+ def flush_queue (queue)
259
+
260
+ count = 0
261
+
262
+ while true
263
+
264
+ l = get_messages(queue, :timeout => 0, :count => 255)
265
+ break if l.length < 1
266
+
267
+ l.each do |m|
268
+ m.delete
269
+ count += 1
270
+ end
271
+ end
272
+
273
+ return count
274
+ end
275
+
276
+ #
277
+ # Deletes the queue. Returns true if the delete was successful.
278
+ # You can empty a queue by called the method #flush_queue
279
+ #
280
+ # If 'force' is set to true, a flush will be performed on the
281
+ # queue before the actual delete operation. It should ensure
282
+ # a successful removal of the queue.
283
+ #
284
+ def delete_queue (queue, force=false)
285
+
286
+ queue = resolve_queue(queue)
287
+
288
+ flush_queue(queue) if force
289
+
290
+ begin
291
+
292
+ doc = do_action :delete, @queue_host, queue.path
293
+
294
+ rescue Exception => e
295
+
296
+ return false if e.message.match "^400 .*$"
297
+ end
298
+
299
+ SQS::get_element_text(doc, "//StatusCode") == "Success"
300
+ end
301
+
302
+ #
303
+ # Given a queue name, a Queue instance is returned.
304
+ #
305
+ def get_queue (queue_name)
306
+
307
+ l = list_queues(queue_name)
308
+
309
+ l.each do |q|
310
+ return q if q.name == queue_name
311
+ end
312
+
313
+ #return nil
314
+ raise "found no queue named '#{queue_name}'"
315
+ end
316
+
317
+ protected
318
+
319
+ #
320
+ # 'queue' might be a Queue instance or a queue name.
321
+ # If it's a Queue instance, it is immediately returned,
322
+ # else the Queue instance is looked up and returned.
323
+ #
324
+ def resolve_queue (queue)
325
+ return queue if queue.kind_of? Queue
326
+ return get_queue(queue.to_s)
327
+ end
328
+
329
+ #
330
+ # The actual http request/response job is done here.
331
+ #
332
+ def do_action (action, host, path, content=nil)
333
+
334
+ #puts "___path : #{path}"
335
+
336
+ doc = nil
337
+
338
+ http = Net::HTTP.new(host)
339
+ http.start do
340
+
341
+ date = Time.now.httpdate
342
+
343
+ req = if action == :get
344
+ Net::HTTP::Get.new(path)
345
+ elsif action == :post
346
+ Net::HTTP::Post.new(path)
347
+ elsif action == :put
348
+ Net::HTTP::Put.new(path)
349
+ else #action == :delete
350
+ Net::HTTP::Delete.new(path)
351
+ end
352
+
353
+ req['AWS-Version'] = AWS_VERSION
354
+ req['Date'] = date
355
+ req['Content-type'] = 'text/plain'
356
+
357
+ if action == :put or action == :post
358
+ req.body = content
359
+ req['Content-length'] = content.length.to_s if content
360
+ end
361
+
362
+ req['Authorization'] = generate_auth_header(
363
+ action, path, date, "text/plain")
364
+
365
+ #req.each_header do |k, v|
366
+ # puts " - '#{k}' => '#{v}'"
367
+ #end
368
+
369
+ res = http.request(req)
370
+
371
+ case res
372
+ when Net::HTTPSuccess, Net::HTTPRedirection
373
+ doc = REXML::Document.new(res.read_body)
374
+ else
375
+ res.error!
376
+ end
377
+ end
378
+ raise_errors(doc)
379
+ return doc
380
+ end
381
+
382
+ #
383
+ # Scans the SQS XML reply for potential errors and raises an
384
+ # error if he encounters one.
385
+ #
386
+ def raise_errors (doc)
387
+
388
+ doc.elements.each("//Error") do |e|
389
+
390
+ code = get_element_text(e, "Code")
391
+ return unless code
392
+
393
+ message = get_element_text(e, "Message")
394
+ raise "SQS::#{code} : #{m.text.to_s}"
395
+ end
396
+ end
397
+
398
+ #
399
+ # Generates the 'AWS x:y" authorization header value.
400
+ #
401
+ def generate_auth_header (action, path, date, content_type)
402
+
403
+ s = ""
404
+ s << action.to_s.upcase
405
+ s << "\n"
406
+
407
+ #s << Base64.encode64(Digest::MD5.digest(content)).strip \
408
+ # if content
409
+ #
410
+ # documented but not necessary (not working)
411
+ s << "\n"
412
+
413
+ s << content_type
414
+ s << "\n"
415
+
416
+ s << date
417
+ s << "\n"
418
+
419
+ i = path.index '?'
420
+ path = path[0..i-1] if i
421
+ s << path
422
+
423
+ #puts ">>>#{s}<<<"
424
+
425
+ digest = OpenSSL::Digest::Digest.new 'sha1'
426
+
427
+ key = ENV['AMAZON_SECRET_ACCESS_KEY']
428
+
429
+ raise "No $AMAZON_SECRET_ACCESS_KEY env variable found" \
430
+ unless key
431
+
432
+ sig = OpenSSL::HMAC.digest(digest, key, s)
433
+ sig = Base64.encode64(sig).strip
434
+
435
+ "AWS #{ENV['AMAZON_ACCESS_KEY_ID']}:#{sig}"
436
+ end
437
+
438
+ end
439
+
440
+ #
441
+ # A convenience method for returning the text of a sub element,
442
+ # maybe there is something better in REXML, but I haven't found out
443
+ # yet.
444
+ #
445
+ def SQS.get_element_text (parent_elt, elt_name)
446
+ e = parent_elt.elements[elt_name]
447
+ return nil unless e
448
+ return e.text.to_s
449
+ end
450
+ end
451
+
452
+
453
+ #
454
+ # running directly...
455
+
456
+ if $0 == __FILE__
457
+
458
+ if ENV['AMAZON_ACCESS_KEY_ID'] == nil or ENV['AMAZON_SECRET_ACCESS_KEY'] == nil
459
+
460
+ puts
461
+ puts "env variables $AMAZON_ACCESS_KEY_ID and $AMAZON_SECRET_ACCESS_KEY are not set"
462
+ puts
463
+ exit 1
464
+ end
465
+
466
+ ACTIONS = {
467
+ :list_queues => :list_queues,
468
+ :lq => :list_queues,
469
+ :create_queue => :create_queue,
470
+ :cq => :create_queue,
471
+ :delete_queue => :delete_queue,
472
+ :dq => :delete_queue,
473
+ :flush_queue => :flush_queue,
474
+ :fq => :flush_queue,
475
+ :get_message => :get_message,
476
+ :gm => :get_message,
477
+ :delete_message => :delete_message,
478
+ :dm => :delete_message,
479
+ :puts_message => :put_message,
480
+ :pm => :put_message
481
+ }
482
+
483
+ b64 = false
484
+ queue_host = nil
485
+
486
+ require 'optparse'
487
+
488
+ opts = OptionParser.new
489
+
490
+ opts.banner = "Usage: sqs.rb [options] {action} [queue_name] [message_id]"
491
+ opts.separator("")
492
+ opts.separator(" known actions are :")
493
+ opts.separator("")
494
+
495
+ keys = ACTIONS.keys.collect { |k| k.to_s }.sort
496
+ keys.each { |k| opts.separator(" - '#{k}' (#{ACTIONS[k.intern]})") }
497
+
498
+ opts.separator("")
499
+ opts.separator(" options are :")
500
+ opts.separator("")
501
+
502
+ opts.on("-H", "--host", "AWS queue host") do |host|
503
+ queue_host = host
504
+ end
505
+
506
+ opts.on("-h", "--help", "displays this help / usage") do
507
+ STDERR.puts "\n#{opts.to_s}\n"
508
+ exit 0
509
+ end
510
+
511
+ opts.on("-b", "--base64", "encode/decode messages with base64") do
512
+ b64 = true
513
+ end
514
+
515
+ argv = opts.parse(ARGV)
516
+
517
+ if argv.length < 1
518
+ STDERR.puts "\n#{opts.to_s}\n"
519
+ exit 0
520
+ end
521
+
522
+ a = argv[0]
523
+ queue_name = argv[1]
524
+ message_id = argv[2]
525
+
526
+ action = ACTIONS[a.intern]
527
+
528
+ unless action
529
+ STDERR.puts "unknown action '#{a}'"
530
+ exit 1
531
+ end
532
+
533
+ qs = SQS::QueueService.new
534
+
535
+ STDERR.puts "#{action.to_s}..."
536
+
537
+ #
538
+ # just do it
539
+
540
+ case action
541
+ when :list_queues, :create_queue, :delete_queue, :flush_queue
542
+
543
+ pp qs.send(action, queue_name)
544
+
545
+ when :get_message
546
+
547
+ if message_id
548
+ m = qs.get_message(queue_name, message_id)
549
+ body = m.message_body
550
+ body = Base64.decode64(body) if b64
551
+ puts body
552
+ else
553
+ pp qs.get_messages(queue_name, :timeout => 0, :count => 255)
554
+ end
555
+
556
+ when :delete_message
557
+
558
+ raise "argument 'message_id' is missing" unless message_id
559
+ pp qs.delete_message(queue_name, message_id)
560
+
561
+ when :put_message
562
+
563
+ message = argv[2]
564
+
565
+ unless message
566
+ message = ""
567
+ while true
568
+ s = STDIN.gets()
569
+ break if s == nil
570
+ message += s[0..-2]
571
+ end
572
+ end
573
+
574
+ message = Base64.encode64(message).strip if b64
575
+
576
+ pp qs.put_message(queue_name, message)
577
+ else
578
+
579
+ STDERR.puts "not yet implemented..."
580
+ end
581
+ end
582
+