totty-amqp 0.6.7.1.totty
Sign up to get free protection for your applications and to get access to all the features.
- data/README +143 -0
- data/Rakefile +20 -0
- data/amqp.todo +32 -0
- data/doc/EXAMPLE_01_PINGPONG +2 -0
- data/doc/EXAMPLE_02_CLOCK +2 -0
- data/doc/EXAMPLE_03_STOCKS +2 -0
- data/doc/EXAMPLE_04_MULTICLOCK +2 -0
- data/doc/EXAMPLE_05_ACK +2 -0
- data/doc/EXAMPLE_05_POP +2 -0
- data/doc/EXAMPLE_06_HASHTABLE +2 -0
- data/examples/amqp/simple.rb +79 -0
- data/examples/mq/ack.rb +45 -0
- data/examples/mq/clock.rb +56 -0
- data/examples/mq/hashtable.rb +52 -0
- data/examples/mq/internal.rb +49 -0
- data/examples/mq/logger.rb +88 -0
- data/examples/mq/multiclock.rb +49 -0
- data/examples/mq/pingpong.rb +45 -0
- data/examples/mq/pop.rb +43 -0
- data/examples/mq/primes-simple.rb +19 -0
- data/examples/mq/primes.rb +99 -0
- data/examples/mq/stocks.rb +58 -0
- data/lib/amqp/buffer.rb +395 -0
- data/lib/amqp/client.rb +210 -0
- data/lib/amqp/frame.rb +124 -0
- data/lib/amqp/protocol.rb +212 -0
- data/lib/amqp/server.rb +99 -0
- data/lib/amqp/spec.rb +832 -0
- data/lib/amqp/version.rb +3 -0
- data/lib/amqp.rb +152 -0
- data/lib/ext/blankslate.rb +7 -0
- data/lib/ext/em.rb +8 -0
- data/lib/ext/emfork.rb +69 -0
- data/lib/mq/exchange.rb +314 -0
- data/lib/mq/header.rb +33 -0
- data/lib/mq/logger.rb +89 -0
- data/lib/mq/queue.rb +455 -0
- data/lib/mq/rpc.rb +100 -0
- data/lib/mq.rb +877 -0
- data/old/README +30 -0
- data/old/Rakefile +12 -0
- data/old/amqp-0.8.json +606 -0
- data/old/amqp_spec.rb +796 -0
- data/old/amqpc.rb +695 -0
- data/old/codegen.rb +148 -0
- data/protocol/amqp-0.8.json +617 -0
- data/protocol/amqp-0.8.xml +3908 -0
- data/protocol/codegen.rb +173 -0
- data/protocol/doc.txt +281 -0
- data/research/api.rb +88 -0
- data/research/primes-forked.rb +63 -0
- data/research/primes-processes.rb +135 -0
- data/research/primes-threaded.rb +49 -0
- data/totty-amqp.gemspec +87 -0
- metadata +142 -0
data/README
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
What AMQP gem is
|
2
|
+
===================
|
3
|
+
|
4
|
+
Simple asynchronous AMQP driver for Ruby/EventMachine
|
5
|
+
This library works with Ruby 1.8, Ruby 1.9, JRuby and Rubinius, and is licensed under [the Ruby License](http://www.ruby-lang.org/en/LICENSE.txt).
|
6
|
+
|
7
|
+
This library was tested primarily with RabbitMQ, although it should be compatible with any
|
8
|
+
server implementing the [AMQP 0-8 spec](http://www.amqp.org/confluence/download/attachments/720900/amqp0-8.pdf).
|
9
|
+
|
10
|
+
Getting started
|
11
|
+
===============
|
12
|
+
|
13
|
+
To use examples with RabbitMQ, first [install the broker](http://www.rabbitmq.com/install.html). If you have Mercurial
|
14
|
+
and Erlang/OTP installed, here is how to do it in 4 lines:
|
15
|
+
|
16
|
+
hg clone http://hg.rabbitmq.com/rabbitmq-codegen
|
17
|
+
hg clone http://hg.rabbitmq.com/rabbitmq-server
|
18
|
+
cd rabbitmq-server
|
19
|
+
make run
|
20
|
+
|
21
|
+
Then have a look at the various bundled examples:
|
22
|
+
|
23
|
+
ruby examples/mq/pingpong.rb # 1-1 communication using amq.direct
|
24
|
+
ruby examples/mq/clock.rb # 1-N communication using amq.fanout
|
25
|
+
ruby examples/mq/stocks.rb # 1-subscriber communication using amq.topic
|
26
|
+
|
27
|
+
ruby examples/mq/multiclock.rb # header based routing (new rabbitmq feature)
|
28
|
+
ruby examples/mq/ack.rb # using ack
|
29
|
+
ruby examples/mq/pop.rb # pop off messages one at a time
|
30
|
+
|
31
|
+
ruby examples/mq/hashtable.rb # simple async rpc layer
|
32
|
+
ruby examples/mq/primes.rb 4 # parallelized prime number generation
|
33
|
+
ruby examples/mq/logger.rb # simple logging api
|
34
|
+
|
35
|
+
For high level API documentation see MQ class.
|
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
|
+
How to use AMQP gem with Ruby on Rails, Merb, Sinatra and other web frameworks
|
45
|
+
==============================================================================
|
46
|
+
|
47
|
+
To use AMQP gem from web applications, you would need to have EventMachine reactor running.
|
48
|
+
If you use [Thin](http://code.macournoyer.com/thin/), you are set: Thin uses EventMachine under
|
49
|
+
the hook.
|
50
|
+
|
51
|
+
With other web servers, you need to start EventMachine reactor in it's own thread like this:
|
52
|
+
|
53
|
+
Thread.new { EM.run }
|
54
|
+
|
55
|
+
because otherwise EventMachine will block current thread. Then connect to AMQP broker:
|
56
|
+
|
57
|
+
AMQP.connect(:host => "localhost", :user => "guest", :pass => "guest", :vhost => "/")
|
58
|
+
|
59
|
+
In a Ruby on Rails app, probably the best place for this code is initializer
|
60
|
+
(like config/initializers/amqp.rb). For Merb apps, it is config/init.rb. For
|
61
|
+
Sinatra and pure Rack applications, place it next to other configuration
|
62
|
+
code.
|
63
|
+
|
64
|
+
Same separate thread technique can be used to make EventMachine play nicely with other
|
65
|
+
libraries that would block current thread (like [File::Tail](http://rubygems.org/gems/file-tail)).
|
66
|
+
|
67
|
+
AMQP gem mailing list
|
68
|
+
==============================
|
69
|
+
|
70
|
+
* [AMQP gem mailing list](http://groups.google.com/group/ruby-amqp)
|
71
|
+
* [AMQP gem at GitHub](http://github.com/tmm1/amqp)
|
72
|
+
* [AMQP gem at Gemcutter](http://rubygems.org/gems/amqp)
|
73
|
+
|
74
|
+
Running specifications suite
|
75
|
+
============================
|
76
|
+
|
77
|
+
To run the test suite make sure you have [bacon](http://gemcutter.org/gems/bacon) gem installed and run:
|
78
|
+
|
79
|
+
rake spec
|
80
|
+
|
81
|
+
The lib/amqp/spec.rb file is generated automatically based on the [AMQP specification](http://www.amqp.org/confluence/display/AMQP/AMQP+Specification). To generate it:
|
82
|
+
|
83
|
+
rake codegen
|
84
|
+
|
85
|
+
Credits and more information
|
86
|
+
============================
|
87
|
+
|
88
|
+
(c) 2008—2010 [Aman Gupta](http://github.com/tmm1) (tmm1)
|
89
|
+
|
90
|
+
This project was inspired by [py-amqplib](http://barryp.org/software/py-amqplib/), [rabbitmq](http://rabbitmq.com), [qpid](http://qpid.apache.org/) and [rubbyt](http://github.com/rubbyt/rubbyt).
|
91
|
+
Special thanks to Dmitriy Samovskiy, Ben Hood and Tony Garnock-Jones.
|
92
|
+
|
93
|
+
AMQP brokers
|
94
|
+
------------
|
95
|
+
|
96
|
+
* [RabbitMQ](http://rabbitmq.com) (Rabbit Technologies, Erlang/OTP, MPL)
|
97
|
+
* [ZeroMQ](http://www.zeromq.org) (iMatix/FastMQ/Intel, C++, GPL3)
|
98
|
+
* [OpenAMQ](http://openamq.org) (iMatix, C, GPL2)
|
99
|
+
* [ActiveMQ](http://activemq.apache.org) (Apache Foundation, Java, Apache2)
|
100
|
+
|
101
|
+
AMQP resources
|
102
|
+
--------------
|
103
|
+
|
104
|
+
* Steve Vinoski [explains AMQP](http://steve.vinoski.net/pdf/IEEE-Advanced_Message_Queuing_Protocol.pdf) in his column, Towards Integration
|
105
|
+
|
106
|
+
* John O'Hara on [the history of AMQP](http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=485)
|
107
|
+
|
108
|
+
* Dmitriy's [presentation on RabbitMQ/AMQP](http://somic-org.homelinux.org/blog/2008/07/31/slides-for-my-amqprabbitmq-talk/)
|
109
|
+
|
110
|
+
* ZeroMQ's [analysis of the messaging technology market](http://www.zeromq.org/whitepapers:market-analysis)
|
111
|
+
|
112
|
+
* Pieter Hintjens's [background to AMQP](http://www.openamq.org/doc:amqp-background)
|
113
|
+
|
114
|
+
* Barry Pederson's [py-amqplib](http://barryp.org/software/py-amqplib/)
|
115
|
+
|
116
|
+
* Ben Hood on [writing an AMQP client](http://hopper.squarespace.com/blog/2008/6/21/build-your-own-amqp-client.html)
|
117
|
+
|
118
|
+
* Dmitriy Samovskiy introduces [Ruby + QPid + RabbitMQ](http://somic-org.homelinux.org/blog/2008/06/24/ruby-amqp-rabbitmq-example/)
|
119
|
+
|
120
|
+
* Ben Hood's [as3-amqp](http://github.com/0x6e6562/as3-amqp) ([two](http://hopper.squarespace.com/blog/2008/7/4/server-side-as3.html), [three](http://hopper.squarespace.com/blog/2008/3/24/as3-amqp-client-first-cut.html))
|
121
|
+
|
122
|
+
* RabbitMQ's [AMQP protocol code generator](http://hg.rabbitmq.com/rabbitmq-codegen/)
|
123
|
+
|
124
|
+
* Erlang Exchange [presentation on the implementation of RabbitMQ](http://skillsmatter.com/podcast/erlang/presenting-rabbitmq-an-erlang-based-implementatio-nof-amqp) (and on the [LShift blog](http://www.lshift.net/blog/2008/07/01/slides-from-our-erlang-exchange-talk))
|
125
|
+
|
126
|
+
* Jonathan Conway's series on RabbitMQ and using it with Ruby and Merb: [One](http://jaikoo.com/2007/9/4/didn-t-you-get-the-memo), [Two](http://jaikoo.com/2008/2/29/friday-round-up-2008-02-29), [Three](http://jaikoo.com/2008/3/14/oh-hai-rabbitmq), [Four](http://jaikoo.com/2008/3/20/daemonize-rabbitmq)
|
127
|
+
|
128
|
+
* Open Enterprise's series on messaging middleware and AMQP: [Part 1](http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-1.html), [Part 2](http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-2.html), [Part 3](http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-3.html)
|
129
|
+
|
130
|
+
Messaging and distributed systems resources
|
131
|
+
-------------------------------------------
|
132
|
+
|
133
|
+
* [A Critique of the Remote Procedure Call Paradigm](http://www.cs.vu.nl/~ast/publications/euteco-1988.pdf)
|
134
|
+
|
135
|
+
* [A Note on Distributed Computing](http://research.sun.com/techrep/1994/smli_tr-94-29.pdf)
|
136
|
+
|
137
|
+
* [Convenience Over Correctness](http://steve.vinoski.net/pdf/IEEE-Convenience_Over_Correctness.pdf)
|
138
|
+
|
139
|
+
* [Metaprotocol Taxonomy and Communications Patterns](http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp)
|
140
|
+
|
141
|
+
* Joe Armstrong on [Erlang messaging vs RPC](http://armstrongonsoftware.blogspot.com/2008/05/road-we-didnt-go-down.html)
|
142
|
+
|
143
|
+
* [SEDA: scalable internet services using message queues](http://www.eecs.harvard.edu/~mdw/papers/seda-sosp01.pdf)
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
desc "Generate AMQP specification classes"
|
2
|
+
task :codegen do
|
3
|
+
sh 'ruby protocol/codegen.rb > lib/amqp/spec.rb'
|
4
|
+
sh 'ruby lib/amqp/spec.rb'
|
5
|
+
end
|
6
|
+
|
7
|
+
desc "Run spec suite (uses bacon gem)"
|
8
|
+
task :spec do
|
9
|
+
sh 'bacon lib/amqp.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Build the gem"
|
13
|
+
task :gem do
|
14
|
+
sh 'gem build *.gemspec'
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Synonym for gem"
|
18
|
+
task :pkg => :gem
|
19
|
+
desc "Synonym for gem"
|
20
|
+
task :package => :gem
|
data/amqp.todo
ADDED
@@ -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
|
data/doc/EXAMPLE_05_ACK
ADDED
data/doc/EXAMPLE_05_POP
ADDED
@@ -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
|
+
}
|
data/examples/mq/ack.rb
ADDED
@@ -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]
|
@@ -0,0 +1,52 @@
|
|
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
|
+
class HashTable < Hash
|
13
|
+
def get key
|
14
|
+
log 'HashTable', :get, key
|
15
|
+
self[key]
|
16
|
+
end
|
17
|
+
|
18
|
+
def set key, value
|
19
|
+
log 'HashTable', :set, key => value
|
20
|
+
self[key] = value
|
21
|
+
end
|
22
|
+
|
23
|
+
def keys
|
24
|
+
log 'HashTable', :keys
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
server = MQ.new.rpc('hash table node', HashTable.new)
|
30
|
+
|
31
|
+
client = MQ.new.rpc('hash table node')
|
32
|
+
client.set(:now, time = Time.now)
|
33
|
+
client.get(:now) do |res|
|
34
|
+
log 'client', :now => res, :eql? => res == time
|
35
|
+
end
|
36
|
+
|
37
|
+
client.set(:one, 1)
|
38
|
+
client.keys do |res|
|
39
|
+
log 'client', :keys => res
|
40
|
+
AMQP.stop{ EM.stop }
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
__END__
|
46
|
+
|
47
|
+
["HashTable", :set, {:now=>Thu Jul 17 21:04:53 -0700 2008}]
|
48
|
+
["HashTable", :get, :now]
|
49
|
+
["HashTable", :set, {:one=>1}]
|
50
|
+
["HashTable", :keys]
|
51
|
+
["client", {:eql?=>true, :now=>Thu Jul 17 21:04:53 -0700 2008}]
|
52
|
+
["client", {:keys=>[:one, :now]}]
|
@@ -0,0 +1,49 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
|
+
require 'mq'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
EM.run do
|
6
|
+
|
7
|
+
# connect to the amqp server
|
8
|
+
connection = AMQP.connect(:host => 'localhost', :logging => false)
|
9
|
+
|
10
|
+
# open a channel on the AMQP connection
|
11
|
+
channel = MQ.new(connection)
|
12
|
+
|
13
|
+
# declare a queue on the channel
|
14
|
+
queue = MQ::Queue.new(channel, 'queue name')
|
15
|
+
|
16
|
+
# create a fanout exchange
|
17
|
+
exchange = MQ::Exchange.new(channel, :fanout, 'all queues')
|
18
|
+
|
19
|
+
# bind the queue to the exchange
|
20
|
+
queue.bind(exchange)
|
21
|
+
|
22
|
+
# publish a message to the exchange
|
23
|
+
exchange.publish('hello world')
|
24
|
+
|
25
|
+
# subscribe to messages in the queue
|
26
|
+
queue.subscribe do |headers, msg|
|
27
|
+
pp [:got, headers, msg]
|
28
|
+
connection.close{ EM.stop_event_loop }
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
__END__
|
34
|
+
|
35
|
+
[:got,
|
36
|
+
#<AMQP::Protocol::Header:0x1186270
|
37
|
+
@klass=AMQP::Protocol::Basic,
|
38
|
+
@properties=
|
39
|
+
{:priority=>0,
|
40
|
+
:exchange=>"all queues",
|
41
|
+
:consumer_tag=>"queue name",
|
42
|
+
:delivery_tag=>1,
|
43
|
+
:delivery_mode=>1,
|
44
|
+
:redelivered=>false,
|
45
|
+
:content_type=>"application/octet-stream",
|
46
|
+
:routing_key=>""},
|
47
|
+
@size=11,
|
48
|
+
@weight=0>,
|
49
|
+
"hello world"]
|
@@ -0,0 +1,88 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
|
+
require 'mq'
|
3
|
+
require 'mq/logger'
|
4
|
+
|
5
|
+
Logger = MQ::Logger
|
6
|
+
|
7
|
+
AMQP.start(:host => 'localhost') do
|
8
|
+
if ARGV[0] == 'server'
|
9
|
+
|
10
|
+
MQ.queue('logger').bind(MQ.fanout('logging', :durable => true)).subscribe{|msg|
|
11
|
+
msg = Marshal.load(msg)
|
12
|
+
require 'pp'
|
13
|
+
pp(msg)
|
14
|
+
puts
|
15
|
+
}
|
16
|
+
|
17
|
+
elsif ARGV[0] == 'client'
|
18
|
+
|
19
|
+
log = Logger.new
|
20
|
+
log.debug 'its working!'
|
21
|
+
|
22
|
+
log = Logger.new do |msg|
|
23
|
+
require 'pp'
|
24
|
+
pp msg
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
|
28
|
+
log.info '123'
|
29
|
+
log.debug [1,2,3]
|
30
|
+
log.debug :one => 1, :two => 2
|
31
|
+
log.error Exception.new('123')
|
32
|
+
|
33
|
+
log.info '123', :process_id => Process.pid
|
34
|
+
log.info '123', :process
|
35
|
+
log.debug 'login', :session => 'abc', :user => 123
|
36
|
+
|
37
|
+
log = Logger.new(:webserver, :timestamp, :hostname, &log.printer)
|
38
|
+
log.info 'Request for /', :GET, :session => 'abc'
|
39
|
+
|
40
|
+
AMQP.stop{ EM.stop }
|
41
|
+
|
42
|
+
else
|
43
|
+
|
44
|
+
puts
|
45
|
+
puts "#{$0} <client|server>"
|
46
|
+
puts " client: send logs to message queue"
|
47
|
+
puts " server: read logs from message queue"
|
48
|
+
puts
|
49
|
+
|
50
|
+
EM.stop
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
__END__
|
56
|
+
|
57
|
+
{:data=>"123", :timestamp=>1216846102, :severity=>:info}
|
58
|
+
|
59
|
+
{:data=>[1, 2, 3], :timestamp=>1216846102, :severity=>:debug}
|
60
|
+
|
61
|
+
{:data=>
|
62
|
+
{:type=>:exception, :name=>:Exception, :message=>"123", :backtrace=>nil},
|
63
|
+
:timestamp=>1216846102,
|
64
|
+
:severity=>:error}
|
65
|
+
|
66
|
+
{:data=>"123", :timestamp=>1216846102, :process_id=>1814, :severity=>:info}
|
67
|
+
|
68
|
+
{:process=>
|
69
|
+
{:thread_id=>109440,
|
70
|
+
:process_id=>1814,
|
71
|
+
:process_name=>"/Users/aman/code/amqp/examples/logger.rb",
|
72
|
+
:process_parent_id=>1813},
|
73
|
+
:data=>"123",
|
74
|
+
:timestamp=>1216846102,
|
75
|
+
:severity=>:info}
|
76
|
+
|
77
|
+
{:session=>"abc",
|
78
|
+
:data=>"login",
|
79
|
+
:timestamp=>1216846102,
|
80
|
+
:severity=>:debug,
|
81
|
+
:user=>123}
|
82
|
+
|
83
|
+
{:session=>"abc",
|
84
|
+
:tags=>[:webserver, :GET],
|
85
|
+
:data=>"Request for /",
|
86
|
+
:timestamp=>1216846102,
|
87
|
+
:severity=>:info,
|
88
|
+
:hostname=>"gc"}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
|
+
require 'mq'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
AMQP.start(:host => 'localhost') do
|
6
|
+
|
7
|
+
def log *args
|
8
|
+
p args
|
9
|
+
end
|
10
|
+
|
11
|
+
#AMQP.logging = true
|
12
|
+
|
13
|
+
clock = MQ.new.headers('multiformat_clock')
|
14
|
+
EM.add_periodic_timer(1){
|
15
|
+
puts
|
16
|
+
|
17
|
+
time = Time.new
|
18
|
+
["iso8601","rfc2822"].each do |format|
|
19
|
+
formatted_time = time.send(format)
|
20
|
+
log :publish, format, formatted_time
|
21
|
+
clock.publish "#{formatted_time}", :headers => {"format" => format}
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
["iso8601","rfc2822"].each do |format|
|
26
|
+
amq = MQ.new
|
27
|
+
amq.queue(format.to_s).bind(amq.headers('multiformat_clock'), :arguments => {"format" => format}).subscribe{ |time|
|
28
|
+
log "received #{format}", time
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
__END__
|
35
|
+
|
36
|
+
[:publish, "iso8601", "2009-02-13T19:55:40-08:00"]
|
37
|
+
[:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:40 -0800"]
|
38
|
+
["received iso8601", "2009-02-13T19:55:40-08:00"]
|
39
|
+
["received rfc2822", "Fri, 13 Feb 2009 19:55:40 -0800"]
|
40
|
+
|
41
|
+
[:publish, "iso8601", "2009-02-13T19:55:41-08:00"]
|
42
|
+
[:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:41 -0800"]
|
43
|
+
["received iso8601", "2009-02-13T19:55:41-08:00"]
|
44
|
+
["received rfc2822", "Fri, 13 Feb 2009 19:55:41 -0800"]
|
45
|
+
|
46
|
+
[:publish, "iso8601", "2009-02-13T19:55:42-08:00"]
|
47
|
+
[:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:42 -0800"]
|
48
|
+
["received iso8601", "2009-02-13T19:55:42-08:00"]
|
49
|
+
["received rfc2822", "Fri, 13 Feb 2009 19:55:42 -0800"]
|