adamh-amqp 0.6.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/README +128 -0
  2. data/Rakefile +15 -0
  3. data/amqp.gemspec +83 -0
  4. data/amqp.todo +32 -0
  5. data/doc/EXAMPLE_01_PINGPONG +2 -0
  6. data/doc/EXAMPLE_02_CLOCK +2 -0
  7. data/doc/EXAMPLE_03_STOCKS +2 -0
  8. data/doc/EXAMPLE_04_MULTICLOCK +2 -0
  9. data/doc/EXAMPLE_05_ACK +2 -0
  10. data/doc/EXAMPLE_05_POP +2 -0
  11. data/doc/EXAMPLE_06_HASHTABLE +2 -0
  12. data/examples/amqp/simple.rb +79 -0
  13. data/examples/mq/ack.rb +45 -0
  14. data/examples/mq/clock.rb +56 -0
  15. data/examples/mq/hashtable.rb +52 -0
  16. data/examples/mq/internal.rb +49 -0
  17. data/examples/mq/logger.rb +88 -0
  18. data/examples/mq/multiclock.rb +49 -0
  19. data/examples/mq/pingpong.rb +45 -0
  20. data/examples/mq/pop.rb +43 -0
  21. data/examples/mq/primes-simple.rb +19 -0
  22. data/examples/mq/primes.rb +99 -0
  23. data/examples/mq/stocks.rb +58 -0
  24. data/lib/amqp.rb +115 -0
  25. data/lib/amqp/buffer.rb +395 -0
  26. data/lib/amqp/client.rb +210 -0
  27. data/lib/amqp/frame.rb +124 -0
  28. data/lib/amqp/protocol.rb +212 -0
  29. data/lib/amqp/server.rb +99 -0
  30. data/lib/amqp/spec.rb +832 -0
  31. data/lib/ext/blankslate.rb +7 -0
  32. data/lib/ext/em.rb +51 -0
  33. data/lib/ext/emfork.rb +69 -0
  34. data/lib/mq.rb +823 -0
  35. data/lib/mq/exchange.rb +302 -0
  36. data/lib/mq/header.rb +33 -0
  37. data/lib/mq/logger.rb +89 -0
  38. data/lib/mq/queue.rb +433 -0
  39. data/lib/mq/rpc.rb +100 -0
  40. data/old/README +30 -0
  41. data/old/Rakefile +12 -0
  42. data/old/amqp-0.8.json +606 -0
  43. data/old/amqp_spec.rb +796 -0
  44. data/old/amqpc.rb +695 -0
  45. data/old/codegen.rb +148 -0
  46. data/protocol/amqp-0.8.json +617 -0
  47. data/protocol/amqp-0.8.xml +3908 -0
  48. data/protocol/codegen.rb +173 -0
  49. data/protocol/doc.txt +281 -0
  50. data/research/api.rb +88 -0
  51. data/research/primes-forked.rb +63 -0
  52. data/research/primes-processes.rb +135 -0
  53. data/research/primes-threaded.rb +49 -0
  54. metadata +121 -0
data/README ADDED
@@ -0,0 +1,128 @@
1
+ Simple AMQP driver for Ruby/EventMachine
2
+ (c) 2008 Aman Gupta (tmm1)
3
+
4
+ http://github.com/tmm1/amqp
5
+ http://rubyforge.org/projects/amqp
6
+ http://hopper.squarespace.com/blog/2008/7/22/simple-amqp-library-for-ruby.html
7
+ http://groups.google.com/group/ruby-amqp
8
+ http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2008-July/001417.html
9
+
10
+ This library works with Ruby 1.8, Ruby 1.9 and JRuby.
11
+
12
+ This library was tested primarily with RabbitMQ, although it should be compatible with any
13
+ server implementing the AMQP 0-8 spec.
14
+
15
+ To use with RabbitMQ, first run the server:
16
+
17
+ hg clone http://hg.rabbitmq.com/rabbitmq-codegen
18
+ hg clone http://hg.rabbitmq.com/rabbitmq-server
19
+ cd rabbitmq-server
20
+ make run
21
+
22
+ To get started, refer to the various bundled examples:
23
+
24
+ ruby examples/mq/pingpong.rb # 1-1 communication using amq.direct
25
+ ruby examples/mq/clock.rb # 1-N communication using amq.fanout
26
+ ruby examples/mq/stocks.rb # 1-subscriber communication using amq.topic
27
+
28
+ ruby examples/mq/multiclock.rb # header based routing (new rabbitmq feature)
29
+ ruby examples/mq/ack.rb # using ack
30
+ ruby examples/mq/pop.rb # pop off messages one at a time
31
+
32
+ ruby examples/mq/hashtable.rb # simple async rpc layer
33
+ ruby examples/mq/primes.rb 4 # parallelized prime number generation
34
+ ruby examples/mq/logger.rb # simple logging api
35
+
36
+ For more details into the lower level AMQP client API, run the simple client example:
37
+
38
+ ruby examples/amqp/simple.rb # low-level AMQP api
39
+ ruby examples/mq/internal.rb # low-level Queue/Exchange api
40
+
41
+ Or refer to protocol/doc.txt, which enumerates packets sent between a server and client
42
+ during a typical session, in both binary and decoded formats.
43
+
44
+ To run the test suite:
45
+
46
+ rake spec
47
+
48
+ The lib/amqp/spec.rb file is generated automatically based on the AMQP specification. To generate it:
49
+
50
+ rake codegen
51
+
52
+ This project was inspired by py-amqplib, rabbitmq, qpid and rubbyt.
53
+ Special thanks to Dmitriy Samovskiy, Ben Hood and Tony Garnock-Jones.
54
+
55
+ AMQP resources:
56
+
57
+ Servers:
58
+ RabbitMQ (Rabbit Technologies, Erlang/OTP, MPL) - http://rabbitmq.com
59
+ ZeroMQ (iMatix/FastMQ/Intel, C++, GPL3) - http://www.zeromq.org
60
+ OpenAMQ (iMatix, C, GPL2) - http://openamq.org
61
+ ActiveMQ (Apache Foundation, Java, apache2) - http://activemq.apache.org
62
+
63
+ Steve Vinoski explains AMQP in his column, Towards Integration
64
+ http://steve.vinoski.net/pdf/IEEE-Advanced_Message_Queuing_Protocol.pdf
65
+
66
+ John O'Hara on the history of AMQP
67
+ http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=485
68
+
69
+ Dmitriy's presentation on RabbitMQ/AMQP
70
+ http://somic-org.homelinux.org/blog/2008/07/31/slides-for-my-amqprabbitmq-talk/
71
+
72
+ ZeroMQ's analysis of the messaging technology market
73
+ http://www.zeromq.org/whitepapers:market-analysis
74
+
75
+ Pieter Hintjens's background to AMQP
76
+ http://www.openamq.org/doc:amqp-background
77
+
78
+ Barry Pederson's py-amqplib
79
+ http://barryp.org/software/py-amqplib/
80
+
81
+ Ben Hood on writing an AMQP client
82
+ http://hopper.squarespace.com/blog/2008/6/21/build-your-own-amqp-client.html
83
+
84
+ Dmitriy Samovskiy introduces Ruby + QPid + RabbitMQ
85
+ http://somic-org.homelinux.org/blog/2008/06/24/ruby-amqp-rabbitmq-example/
86
+
87
+ Ben Hood's as3-amqp
88
+ http://github.com/0x6e6562/as3-amqp
89
+ http://hopper.squarespace.com/blog/2008/7/4/server-side-as3.html
90
+ http://hopper.squarespace.com/blog/2008/3/24/as3-amqp-client-first-cut.html
91
+
92
+ RabbitMQ's protocol code generator
93
+ http://hg.rabbitmq.com/rabbitmq-codegen/
94
+
95
+ Erlang Exchange presentation on the implementation of RabbitMQ
96
+ http://skillsmatter.com/podcast/erlang/presenting-rabbitmq-an-erlang-based-implementatio-nof-amqp
97
+ http://www.lshift.net/blog/2008/07/01/slides-from-our-erlang-exchange-talk
98
+
99
+ Jonathan Conway's series on RabbitMQ and using it with Ruby/Merb
100
+ http://jaikoo.com/2008/3/20/daemonize-rabbitmq
101
+ http://jaikoo.com/2008/3/14/oh-hai-rabbitmq
102
+ http://jaikoo.com/2008/2/29/friday-round-up-2008-02-29
103
+ http://jaikoo.com/2007/9/4/didn-t-you-get-the-memo
104
+
105
+ Open Enterprise's series on messaging middleware and AMQP
106
+ http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-1.html
107
+ http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-2.html
108
+ http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-3.html
109
+
110
+ Messaging and distributed systems resources:
111
+
112
+ A Critique of the Remote Procedure Call Paradigm
113
+ http://www.cs.vu.nl/~ast/publications/euteco-1988.pdf
114
+
115
+ A Note on Distributed Computing
116
+ http://research.sun.com/techrep/1994/smli_tr-94-29.pdf
117
+
118
+ Convenience Over Correctness
119
+ http://steve.vinoski.net/pdf/IEEE-Convenience_Over_Correctness.pdf
120
+
121
+ Metaprotocol Taxonomy and Communications Patterns
122
+ http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp
123
+
124
+ Joe Armstrong on Erlang messaging vs RPC
125
+ http://armstrongonsoftware.blogspot.com/2008/05/road-we-didnt-go-down.html
126
+
127
+ SEDA: scalable internet services using message queues
128
+ http://www.eecs.harvard.edu/~mdw/papers/seda-sosp01.pdf
@@ -0,0 +1,15 @@
1
+ task :codegen do
2
+ sh 'ruby protocol/codegen.rb > lib/amqp/spec.rb'
3
+ sh 'ruby lib/amqp/spec.rb'
4
+ end
5
+
6
+ task :spec do
7
+ sh 'bacon lib/amqp.rb'
8
+ end
9
+
10
+ task :gem do
11
+ sh 'gem build *.gemspec'
12
+ end
13
+
14
+ task :pkg => :gem
15
+ task :package => :gem
@@ -0,0 +1,83 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'amqp'
3
+ s.version = '0.6.3.1'
4
+ s.date = '2009-01-09'
5
+ s.summary = 'AMQP client implementation in Ruby/EventMachine'
6
+ s.email = "amqp@tmm1.net"
7
+ s.homepage = "http://amqp.rubyforge.org/"
8
+ s.description = "AMQP client implementation in Ruby/EventMachine"
9
+ s.has_rdoc = true
10
+ s.rdoc_options = '--include=examples'
11
+
12
+ # ruby -rpp -e' pp `git ls-files`.split("\n").grep(/^(doc|README)/) '
13
+ s.extra_rdoc_files = [
14
+ "README",
15
+ "doc/EXAMPLE_01_PINGPONG",
16
+ "doc/EXAMPLE_02_CLOCK",
17
+ "doc/EXAMPLE_03_STOCKS",
18
+ "doc/EXAMPLE_04_MULTICLOCK",
19
+ "doc/EXAMPLE_05_ACK",
20
+ "doc/EXAMPLE_05_POP",
21
+ "doc/EXAMPLE_06_HASHTABLE"
22
+ ]
23
+
24
+ s.authors = ["Aman Gupta"]
25
+ s.add_dependency('eventmachine', '>= 0.12.4')
26
+
27
+ # ruby -rpp -e' pp `git ls-files`.split("\n") '
28
+ s.files = [
29
+ "README",
30
+ "Rakefile",
31
+ "amqp.gemspec",
32
+ "amqp.todo",
33
+ "doc/EXAMPLE_01_PINGPONG",
34
+ "doc/EXAMPLE_02_CLOCK",
35
+ "doc/EXAMPLE_03_STOCKS",
36
+ "doc/EXAMPLE_04_MULTICLOCK",
37
+ "doc/EXAMPLE_05_ACK",
38
+ "doc/EXAMPLE_05_POP",
39
+ "doc/EXAMPLE_06_HASHTABLE",
40
+ "examples/amqp/simple.rb",
41
+ "examples/mq/ack.rb",
42
+ "examples/mq/clock.rb",
43
+ "examples/mq/pop.rb",
44
+ "examples/mq/hashtable.rb",
45
+ "examples/mq/internal.rb",
46
+ "examples/mq/logger.rb",
47
+ "examples/mq/multiclock.rb",
48
+ "examples/mq/pingpong.rb",
49
+ "examples/mq/primes-simple.rb",
50
+ "examples/mq/primes.rb",
51
+ "examples/mq/stocks.rb",
52
+ "lib/amqp.rb",
53
+ "lib/amqp/buffer.rb",
54
+ "lib/amqp/client.rb",
55
+ "lib/amqp/frame.rb",
56
+ "lib/amqp/protocol.rb",
57
+ "lib/amqp/server.rb",
58
+ "lib/amqp/spec.rb",
59
+ "lib/ext/blankslate.rb",
60
+ "lib/ext/em.rb",
61
+ "lib/ext/emfork.rb",
62
+ "lib/mq.rb",
63
+ "lib/mq/exchange.rb",
64
+ "lib/mq/header.rb",
65
+ "lib/mq/logger.rb",
66
+ "lib/mq/queue.rb",
67
+ "lib/mq/rpc.rb",
68
+ "old/README",
69
+ "old/Rakefile",
70
+ "old/amqp-0.8.json",
71
+ "old/amqp_spec.rb",
72
+ "old/amqpc.rb",
73
+ "old/codegen.rb",
74
+ "protocol/amqp-0.8.json",
75
+ "protocol/amqp-0.8.xml",
76
+ "protocol/codegen.rb",
77
+ "protocol/doc.txt",
78
+ "research/api.rb",
79
+ "research/primes-forked.rb",
80
+ "research/primes-processes.rb",
81
+ "research/primes-threaded.rb"
82
+ ]
83
+ end
@@ -0,0 +1,32 @@
1
+ - breaks with header values that are nil
2
+ - breaks with header values that are ruby objects (convert to strings?)
3
+ - sending utf8 data in 1.9 breaks
4
+
5
+ - generate amqp/spec.rb from original xml spec
6
+ - add peek and pop to queues
7
+ - use rabbitmq generated consumer tag from basic.consume-ok reply
8
+
9
+ - allow temporary queues with amq.queue(nil) syntax (use uuids)
10
+ - use as temp queue in rpc
11
+ - use uuids for message ids in rpc
12
+
13
+ - add ack/completed responses for messages
14
+ - deleting queues/bindings/exchanges
15
+ + queue.unbind
16
+ - queue.remove or queue.close or queue.delete
17
+ - exchange.remove
18
+ - rpc.remove
19
+
20
+ - handle errors and exceptions
21
+ binding to a non-existent (or not yet created in clock.rb) exchange
22
+ #<AMQP::Protocol::Channel::Close:0x11d35d4
23
+ @class_id=50,
24
+ @debug=1,
25
+ @method_id=20,
26
+ @reply_code=404,
27
+ @reply_text="NOT_FOUND - no exchange 'clock' in vhost '/'">>]
28
+
29
+ - handle connection.redirect during connect (for rabbitmq in distributed mode) [or just set insist to true]
30
+
31
+ - add amq.queue('name').size{ |num| "#{num} messages in the queue" } (send declare passive, look at declare-ok response)
32
+ - clean up MQ.default on disconnect
@@ -0,0 +1,2 @@
1
+ == Ping Pong Example
2
+ :include: mq/pingpong.rb
@@ -0,0 +1,2 @@
1
+ == Clock Example
2
+ :include: mq/clock.rb
@@ -0,0 +1,2 @@
1
+ == Stocks Example
2
+ :include: mq/stocks.rb
@@ -0,0 +1,2 @@
1
+ == Muti-format Clock Example
2
+ :include: mq/multiclock.rb
@@ -0,0 +1,2 @@
1
+ == Ack Example
2
+ :include: mq/ack.rb
@@ -0,0 +1,2 @@
1
+ == Pop Example
2
+ :include: mq/pop.rb
@@ -0,0 +1,2 @@
1
+ == HashTable RPC Example
2
+ :include: mq/hashtable.rb
@@ -0,0 +1,79 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'amqp'
3
+
4
+ module SimpleClient
5
+ def process_frame frame
6
+ case frame
7
+ when Frame::Body
8
+ EM.stop_event_loop
9
+
10
+ when Frame::Method
11
+ case method = frame.payload
12
+ when Protocol::Connection::Start
13
+ send Protocol::Connection::StartOk.new({:platform => 'Ruby/EventMachine',
14
+ :product => 'AMQP',
15
+ :information => 'http://github.com/tmm1/amqp',
16
+ :version => '0.1.0'},
17
+ 'AMQPLAIN',
18
+ {:LOGIN => 'guest',
19
+ :PASSWORD => 'guest'},
20
+ 'en_US')
21
+
22
+ when Protocol::Connection::Tune
23
+ send Protocol::Connection::TuneOk.new(:channel_max => 0,
24
+ :frame_max => 131072,
25
+ :heartbeat => 0)
26
+
27
+ send Protocol::Connection::Open.new(:virtual_host => '/',
28
+ :capabilities => '',
29
+ :insist => false)
30
+
31
+ when Protocol::Connection::OpenOk
32
+ send Protocol::Channel::Open.new, :channel => 1
33
+
34
+ when Protocol::Channel::OpenOk
35
+ send Protocol::Access::Request.new(:realm => '/data',
36
+ :read => true,
37
+ :write => true,
38
+ :active => true), :channel => 1
39
+
40
+ when Protocol::Access::RequestOk
41
+ @ticket = method.ticket
42
+ send Protocol::Queue::Declare.new(:ticket => @ticket,
43
+ :queue => '',
44
+ :exclusive => false,
45
+ :auto_delete => true), :channel => 1
46
+
47
+ when Protocol::Queue::DeclareOk
48
+ @queue = method.queue
49
+ send Protocol::Queue::Bind.new(:ticket => @ticket,
50
+ :queue => @queue,
51
+ :exchange => '',
52
+ :routing_key => 'test_route'), :channel => 1
53
+
54
+ when Protocol::Queue::BindOk
55
+ send Protocol::Basic::Consume.new(:ticket => @ticket,
56
+ :queue => @queue,
57
+ :no_local => false,
58
+ :no_ack => true), :channel => 1
59
+
60
+ when Protocol::Basic::ConsumeOk
61
+ data = "this is a test!"
62
+
63
+ send Protocol::Basic::Publish.new(:ticket => @ticket,
64
+ :exchange => '',
65
+ :routing_key => 'test_route'), :channel => 1
66
+ send Protocol::Header.new(Protocol::Basic, data.length, :content_type => 'application/octet-stream',
67
+ :delivery_mode => 1,
68
+ :priority => 0), :channel => 1
69
+ send Frame::Body.new(data), :channel => 1
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ EM.run{
76
+ AMQP.logging = true
77
+ AMQP.client = SimpleClient
78
+ AMQP.start
79
+ }
@@ -0,0 +1,45 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'mq'
3
+
4
+ # For ack to work appropriately you must shutdown AMQP gracefully,
5
+ # otherwise all items in your queue will be returned
6
+ Signal.trap('INT') { AMQP.stop{ EM.stop } }
7
+ Signal.trap('TERM'){ AMQP.stop{ EM.stop } }
8
+
9
+ AMQP.start(:host => 'localhost') do
10
+ MQ.queue('awesome').publish('Totally rad 1')
11
+ MQ.queue('awesome').publish('Totally rad 2')
12
+ MQ.queue('awesome').publish('Totally rad 3')
13
+
14
+ i = 0
15
+
16
+ # Stopping after the second item was acked will keep the 3rd item in the queue
17
+ MQ.queue('awesome').subscribe(:ack => true) do |h,m|
18
+ if (i+=1) == 3
19
+ puts 'Shutting down...'
20
+ AMQP.stop{ EM.stop }
21
+ end
22
+
23
+ if AMQP.closing?
24
+ puts "#{m} (ignored, redelivered later)"
25
+ else
26
+ puts m
27
+ h.ack
28
+ end
29
+ end
30
+ end
31
+
32
+ __END__
33
+
34
+ Totally rad 1
35
+ Totally rad 2
36
+ Shutting down...
37
+ Totally rad 3 (ignored, redelivered later)
38
+
39
+ When restarted:
40
+
41
+ Totally rad 3
42
+ Totally rad 1
43
+ Shutting down...
44
+ Totally rad 2 (ignored, redelivered later)
45
+ Totally rad 3 (ignored, redelivered later)
@@ -0,0 +1,56 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'mq'
3
+
4
+ AMQP.start(:host => 'localhost') do
5
+
6
+ def log *args
7
+ p args
8
+ end
9
+
10
+ # AMQP.logging = true
11
+
12
+ clock = MQ.new.fanout('clock')
13
+ EM.add_periodic_timer(1){
14
+ puts
15
+
16
+ log :publishing, time = Time.now
17
+ clock.publish(Marshal.dump(time))
18
+ }
19
+
20
+ amq = MQ.new
21
+ amq.queue('every second').bind(amq.fanout('clock')).subscribe{ |time|
22
+ log 'every second', :received, Marshal.load(time)
23
+ }
24
+
25
+ amq = MQ.new
26
+ amq.queue('every 5 seconds').bind(amq.fanout('clock')).subscribe{ |time|
27
+ time = Marshal.load(time)
28
+ log 'every 5 seconds', :received, time if time.strftime('%S').to_i%5 == 0
29
+ }
30
+
31
+ end
32
+
33
+ __END__
34
+
35
+ [:publishing, Thu Jul 17 20:14:00 -0700 2008]
36
+ ["every 5 seconds", :received, Thu Jul 17 20:14:00 -0700 2008]
37
+ ["every second", :received, Thu Jul 17 20:14:00 -0700 2008]
38
+
39
+ [:publishing, Thu Jul 17 20:14:01 -0700 2008]
40
+ ["every second", :received, Thu Jul 17 20:14:01 -0700 2008]
41
+
42
+ [:publishing, Thu Jul 17 20:14:02 -0700 2008]
43
+ ["every second", :received, Thu Jul 17 20:14:02 -0700 2008]
44
+
45
+ [:publishing, Thu Jul 17 20:14:03 -0700 2008]
46
+ ["every second", :received, Thu Jul 17 20:14:03 -0700 2008]
47
+
48
+ [:publishing, Thu Jul 17 20:14:04 -0700 2008]
49
+ ["every second", :received, Thu Jul 17 20:14:04 -0700 2008]
50
+
51
+ [:publishing, Thu Jul 17 20:14:05 -0700 2008]
52
+ ["every 5 seconds", :received, Thu Jul 17 20:14:05 -0700 2008]
53
+ ["every second", :received, Thu Jul 17 20:14:05 -0700 2008]
54
+
55
+ [:publishing, Thu Jul 17 20:14:06 -0700 2008]
56
+ ["every second", :received, Thu Jul 17 20:14:06 -0700 2008]