dripdrop 0.2.0 → 0.3.0
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/README.md +10 -1
 - data/VERSION +1 -1
 - data/dripdrop.gemspec +13 -8
 - data/example/agent_test.rb +4 -3
 - data/example/http.rb +1 -1
 - data/example/subclass.rb +54 -0
 - data/example/xreq_xrep.rb +2 -2
 - data/lib/dripdrop/handlers/http.rb +3 -3
 - data/lib/dripdrop/handlers/zeromq.rb +20 -5
 - data/lib/dripdrop/message.rb +110 -33
 - data/lib/dripdrop/node.rb +55 -40
 - data/lib/dripdrop.rb +1 -0
 - data/spec/message_spec.rb +99 -0
 - data/spec/node/http_spec.rb +67 -0
 - data/spec/node/{zmq_pushpull.rb → zmq_pushpull_spec.rb} +4 -5
 - data/spec/node/{zmq_xrepxreq.rb → zmq_xrepxreq_spec.rb} +4 -4
 - data/spec/node_spec.rb +12 -6
 - metadata +13 -8
 
    
        data/README.md
    CHANGED
    
    | 
         @@ -45,10 +45,19 @@ Here's an example of the kind of thing DripDrop makes easy, from [examples/pubsu 
     | 
|
| 
       45 
45 
     | 
    
         | 
| 
       46 
46 
     | 
    
         
             
            Note that these aren't regular ZMQ sockets, and that the HTTP server isn't a regular server. They only speak and respond using DripDrop::Message formatted messages. For HTTP/WebSockets it's JSON that looks like {name: 'name', head: {}, body: anything}, for ZeroMQ it means BERT. There is a raw made that you can use for other message formats, but using DripDrop::Messages makes things easier, and for some socket types (like XREQ/XREP) the predefined format is very useful in matching requests to replies.
         
     | 
| 
       47 
47 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
            Want to see a longer example encapsulating both zmqmachine and eventmachine functionality? Check out [this file](http://github.com/andrewvc/dripdrop-webstats/blob/master/lib/dripdrop-webstats.rb) 
     | 
| 
      
 48 
     | 
    
         
            +
            Want to see a longer example encapsulating both zmqmachine and eventmachine functionality? Check out [this file](http://github.com/andrewvc/dripdrop-webstats/blob/master/lib/dripdrop-webstats.rb).
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            #RDoc
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            RDocs can be found [here](http://www.rdoc.info/github/andrewvc/dripdrop/master/frames). Most of the interesting stuff is in the [Node](http://www.rdoc.info/github/andrewvc/dripdrop/master/DripDrop/Node) and [Message](http://www.rdoc.info/github/andrewvc/dripdrop/master/DripDrop/Message) classes.
         
     | 
| 
       49 
53 
     | 
    
         | 
| 
       50 
54 
     | 
    
         
             
            #How It Works
         
     | 
| 
       51 
55 
     | 
    
         | 
| 
       52 
56 
     | 
    
         
             
            DripDrop encapsulates both zmqmachine, and eventmachine. It provides some sane default messaging choices, using [BERT](http://github.com/blog/531-introducing-bert-and-bert-rpc) (A binary, JSON, like serialization format) and JSON for serialization. While zmqmachine and eventmachine APIs, some convoluted ones, the goal here is to smooth over the bumps, and make them play together nicely.
         
     | 
| 
       53 
57 
     | 
    
         | 
| 
      
 58 
     | 
    
         
            +
            #Contributors
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            Andrew Cholakian: [andrewvc](http://github.com/andrewvc)
         
     | 
| 
      
 61 
     | 
    
         
            +
            John W Higgins: [wishdev](http://github.com/wishdev)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
       54 
63 
     | 
    
         
             
            Copyright (c) 2010 Andrew Cholakian. See LICENSE for details.
         
     | 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            0. 
     | 
| 
      
 1 
     | 
    
         
            +
            0.3.0
         
     | 
    
        data/dripdrop.gemspec
    CHANGED
    
    | 
         @@ -5,11 +5,11 @@ 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            Gem::Specification.new do |s|
         
     | 
| 
       7 
7 
     | 
    
         
             
              s.name = %q{dripdrop}
         
     | 
| 
       8 
     | 
    
         
            -
              s.version = "0. 
     | 
| 
      
 8 
     | 
    
         
            +
              s.version = "0.3.0"
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         
     | 
| 
       11 
11 
     | 
    
         
             
              s.authors = ["Andrew Cholakian"]
         
     | 
| 
       12 
     | 
    
         
            -
              s.date = %q{2010-10- 
     | 
| 
      
 12 
     | 
    
         
            +
              s.date = %q{2010-10-21}
         
     | 
| 
       13 
13 
     | 
    
         
             
              s.description = %q{0MQ App stats}
         
     | 
| 
       14 
14 
     | 
    
         
             
              s.email = %q{andrew@andrewvc.com}
         
     | 
| 
       15 
15 
     | 
    
         
             
              s.extra_rdoc_files = [
         
     | 
| 
         @@ -29,6 +29,7 @@ Gem::Specification.new do |s| 
     | 
|
| 
       29 
29 
     | 
    
         
             
                 "example/http.rb",
         
     | 
| 
       30 
30 
     | 
    
         
             
                 "example/pubsub.rb",
         
     | 
| 
       31 
31 
     | 
    
         
             
                 "example/pushpull.rb",
         
     | 
| 
      
 32 
     | 
    
         
            +
                 "example/subclass.rb",
         
     | 
| 
       32 
33 
     | 
    
         
             
                 "example/xreq_xrep.rb",
         
     | 
| 
       33 
34 
     | 
    
         
             
                 "js/dripdrop.html",
         
     | 
| 
       34 
35 
     | 
    
         
             
                 "js/dripdrop.js",
         
     | 
| 
         @@ -42,8 +43,10 @@ Gem::Specification.new do |s| 
     | 
|
| 
       42 
43 
     | 
    
         
             
                 "lib/dripdrop/handlers/zeromq.rb",
         
     | 
| 
       43 
44 
     | 
    
         
             
                 "lib/dripdrop/message.rb",
         
     | 
| 
       44 
45 
     | 
    
         
             
                 "lib/dripdrop/node.rb",
         
     | 
| 
       45 
     | 
    
         
            -
                 "spec/ 
     | 
| 
       46 
     | 
    
         
            -
                 "spec/node/ 
     | 
| 
      
 46 
     | 
    
         
            +
                 "spec/message_spec.rb",
         
     | 
| 
      
 47 
     | 
    
         
            +
                 "spec/node/http_spec.rb",
         
     | 
| 
      
 48 
     | 
    
         
            +
                 "spec/node/zmq_pushpull_spec.rb",
         
     | 
| 
      
 49 
     | 
    
         
            +
                 "spec/node/zmq_xrepxreq_spec.rb",
         
     | 
| 
       47 
50 
     | 
    
         
             
                 "spec/node_spec.rb",
         
     | 
| 
       48 
51 
     | 
    
         
             
                 "spec/spec_helper.rb"
         
     | 
| 
       49 
52 
     | 
    
         
             
              ]
         
     | 
| 
         @@ -53,10 +56,12 @@ Gem::Specification.new do |s| 
     | 
|
| 
       53 
56 
     | 
    
         
             
              s.rubygems_version = %q{1.3.7}
         
     | 
| 
       54 
57 
     | 
    
         
             
              s.summary = %q{0MQ App Stats}
         
     | 
| 
       55 
58 
     | 
    
         
             
              s.test_files = [
         
     | 
| 
       56 
     | 
    
         
            -
                "spec/ 
     | 
| 
       57 
     | 
    
         
            -
                 "spec/node/ 
     | 
| 
       58 
     | 
    
         
            -
                 "spec/ 
     | 
| 
       59 
     | 
    
         
            -
                 "spec/ 
     | 
| 
      
 59 
     | 
    
         
            +
                "spec/spec_helper.rb",
         
     | 
| 
      
 60 
     | 
    
         
            +
                 "spec/node/http_spec.rb",
         
     | 
| 
      
 61 
     | 
    
         
            +
                 "spec/node/zmq_xrepxreq_spec.rb",
         
     | 
| 
      
 62 
     | 
    
         
            +
                 "spec/node/zmq_pushpull_spec.rb",
         
     | 
| 
      
 63 
     | 
    
         
            +
                 "spec/message_spec.rb",
         
     | 
| 
      
 64 
     | 
    
         
            +
                 "spec/node_spec.rb"
         
     | 
| 
       60 
65 
     | 
    
         
             
              ]
         
     | 
| 
       61 
66 
     | 
    
         | 
| 
       62 
67 
     | 
    
         
             
              if s.respond_to? :specification_version then
         
     | 
    
        data/example/agent_test.rb
    CHANGED
    
    | 
         @@ -1,12 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ##
         
     | 
| 
      
 2 
     | 
    
         
            +
            ##TODO: This badly needs to be rewritten
         
     | 
| 
      
 3 
     | 
    
         
            +
            ##
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       1 
5 
     | 
    
         
             
            require 'rubygems'
         
     | 
| 
       2 
6 
     | 
    
         
             
            require 'dripdrop/agent'
         
     | 
| 
       3 
7 
     | 
    
         | 
| 
       4 
8 
     | 
    
         
             
            agent = DripDrop::Agent.new(ZMQ::PUB,'tcp://127.0.0.1:2900',:connect)
         
     | 
| 
       5 
9 
     | 
    
         | 
| 
       6 
10 
     | 
    
         
             
            loop do
         
     | 
| 
       7 
     | 
    
         
            -
              #Test is the message name, this is the first part of the 0MQ message, used for filtering
         
     | 
| 
       8 
     | 
    
         
            -
              #at the 0MQ sub socket level, :head is always a hash,  :body is freeform
         
     | 
| 
       9 
     | 
    
         
            -
              #EVERYTHING must be serializable to BERT
         
     | 
| 
       10 
11 
     | 
    
         
             
              agent.send_message('test', :body => 'hello', :head => {:key => 'value'})
         
     | 
| 
       11 
12 
     | 
    
         
             
              puts "SEND"
         
     | 
| 
       12 
13 
     | 
    
         
             
              sleep 1
         
     | 
    
        data/example/http.rb
    CHANGED
    
    
    
        data/example/subclass.rb
    ADDED
    
    | 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'dripdrop'
         
     | 
| 
      
 2 
     | 
    
         
            +
            Thread.abort_on_exception = true
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            #We will create a subclass of the Message class
         
     | 
| 
      
 5 
     | 
    
         
            +
            #which will add a timestamp to the header every
         
     | 
| 
      
 6 
     | 
    
         
            +
            #time it is passed around
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            #First our subclass
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            class TimestampedMessage < DripDrop::Message
         
     | 
| 
      
 11 
     | 
    
         
            +
              def self.create_message(*args)
         
     | 
| 
      
 12 
     | 
    
         
            +
                obj = super
         
     | 
| 
      
 13 
     | 
    
         
            +
                obj.head[:timestamps] = []
         
     | 
| 
      
 14 
     | 
    
         
            +
                obj.head[:timestamps] << Time.now
         
     | 
| 
      
 15 
     | 
    
         
            +
                obj
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def self.recreate_message(*args)
         
     | 
| 
      
 19 
     | 
    
         
            +
                obj = super
         
     | 
| 
      
 20 
     | 
    
         
            +
                obj.head[:timestamps] << Time.now.to_s
         
     | 
| 
      
 21 
     | 
    
         
            +
                obj
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            #Define our handlers
         
     | 
| 
      
 26 
     | 
    
         
            +
            #We'll create a batch of 5 push/pull queues them to
         
     | 
| 
      
 27 
     | 
    
         
            +
            #show the timestamp array getting larger
         
     | 
| 
      
 28 
     | 
    
         
            +
            #as we go along
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            DripDrop.default_message_class = TimestampedMessage
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            node = DripDrop::Node.new do
         
     | 
| 
      
 33 
     | 
    
         
            +
              push1 = zmq_push("tcp://127.0.0.1:2201", :bind)
         
     | 
| 
      
 34 
     | 
    
         
            +
              push2 = zmq_push("tcp://127.0.0.1:2202", :bind)
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              pull1 = zmq_pull("tcp://127.0.0.1:2201", :connect)
         
     | 
| 
      
 37 
     | 
    
         
            +
              pull2 = zmq_pull("tcp://127.0.0.1:2202", :connect)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              pull1.on_recv do |msg|
         
     | 
| 
      
 40 
     | 
    
         
            +
                puts "Pull 1 #{msg.head}"
         
     | 
| 
      
 41 
     | 
    
         
            +
                sleep 1
         
     | 
| 
      
 42 
     | 
    
         
            +
                push2.send_message(msg)
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              pull2.on_recv do |msg|
         
     | 
| 
      
 46 
     | 
    
         
            +
                puts "Pull 2 #{msg.head}"
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              push1.send_message(TimestampedMessage.create_message(:name => 'test', :body => "Hello there"))
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            node.start
         
     | 
| 
      
 53 
     | 
    
         
            +
            sleep 5
         
     | 
| 
      
 54 
     | 
    
         
            +
            node.stop
         
     | 
    
        data/example/xreq_xrep.rb
    CHANGED
    
    | 
         @@ -5,9 +5,9 @@ DripDrop::Node.new do 
     | 
|
| 
       5 
5 
     | 
    
         
             
              z_addr = 'tcp://127.0.0.1:2200'
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
              rep = zmq_xrep(z_addr, :bind)
         
     | 
| 
       8 
     | 
    
         
            -
              rep.on_recv do |identities,seq 
     | 
| 
      
 8 
     | 
    
         
            +
              rep.on_recv do |message,identities,seq|
         
     | 
| 
       9 
9 
     | 
    
         
             
                puts "REP #{message.body}"
         
     | 
| 
       10 
     | 
    
         
            -
                rep.send_message(identities,seq 
     | 
| 
      
 10 
     | 
    
         
            +
                rep.send_message(message,identities,seq)
         
     | 
| 
       11 
11 
     | 
    
         
             
              end
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
              req = zmq_xreq(z_addr, :connect)
         
     | 
| 
         @@ -46,7 +46,7 @@ class DripDrop 
     | 
|
| 
       46 
46 
     | 
    
         
             
                      when :dripdrop_json
         
     | 
| 
       47 
47 
     | 
    
         
             
                        msg = DripDrop::Message.decode_json(env['rack.input'].read)
         
     | 
| 
       48 
48 
     | 
    
         
             
                        msg.head[:http_env] = env
         
     | 
| 
       49 
     | 
    
         
            -
                        @recv_cbak.call(body 
     | 
| 
      
 49 
     | 
    
         
            +
                        @recv_cbak.call(msg,body)
         
     | 
| 
       50 
50 
     | 
    
         
             
                      else
         
     | 
| 
       51 
51 
     | 
    
         
             
                        raise "Unsupported message type #{@msg_format}"
         
     | 
| 
       52 
52 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -69,8 +69,8 @@ class DripDrop 
     | 
|
| 
       69 
69 
     | 
    
         
             
                  #Rack middleware was not meant to be used this way...
         
     | 
| 
       70 
70 
     | 
    
         
             
                  #Thin's error handling only rescues stuff w/o a backtrace
         
     | 
| 
       71 
71 
     | 
    
         
             
                  begin
         
     | 
| 
       72 
     | 
    
         
            -
                    Thin::Logging.debug =  
     | 
| 
       73 
     | 
    
         
            -
                    Thin::Logging.trace =  
     | 
| 
      
 72 
     | 
    
         
            +
                    Thin::Logging.debug = false
         
     | 
| 
      
 73 
     | 
    
         
            +
                    Thin::Logging.trace = false
         
     | 
| 
       74 
74 
     | 
    
         
             
                    Thin::Server.start(@address.host, @address.port) do
         
     | 
| 
       75 
75 
     | 
    
         
             
                      map '/' do
         
     | 
| 
       76 
76 
     | 
    
         
             
                        run HTTPApp.new(msg_format,&block)
         
     | 
| 
         @@ -1,6 +1,13 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'ffi-rzmq'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            class DripDrop
         
     | 
| 
      
 4 
     | 
    
         
            +
              #Setup the default message class handler first
         
     | 
| 
      
 5 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :default_message_class
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                DripDrop.default_message_class = DripDrop::Message
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
       4 
11 
     | 
    
         
             
              class ZMQBaseHandler
         
     | 
| 
       5 
12 
     | 
    
         
             
                attr_reader :address, :socket_ctype, :socket
         
     | 
| 
       6 
13 
     | 
    
         | 
| 
         @@ -9,6 +16,7 @@ class DripDrop 
     | 
|
| 
       9 
16 
     | 
    
         
             
                  @zm_reactor   = zm_reactor
         
     | 
| 
       10 
17 
     | 
    
         
             
                  @socket_ctype = socket_ctype # :bind or :connect
         
     | 
| 
       11 
18 
     | 
    
         
             
                  @debug        = opts[:debug] # TODO: Start actually using this
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @opts         = opts
         
     | 
| 
       12 
20 
     | 
    
         
             
                end
         
     | 
| 
       13 
21 
     | 
    
         | 
| 
       14 
22 
     | 
    
         
             
                def on_attach(socket)
         
     | 
| 
         @@ -91,8 +99,15 @@ class DripDrop 
     | 
|
| 
       91 
99 
     | 
    
         
             
              end
         
     | 
| 
       92 
100 
     | 
    
         | 
| 
       93 
101 
     | 
    
         
             
              module ZMQReadableHandler
         
     | 
| 
      
 102 
     | 
    
         
            +
                attr_accessor :message_class
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
       94 
104 
     | 
    
         
             
                def initialize(*args)
         
     | 
| 
       95 
105 
     | 
    
         
             
                  super(*args)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  @message_class = @opts[:msg_class] || DripDrop.default_message_class
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                def decode_message(msg)
         
     | 
| 
      
 110 
     | 
    
         
            +
                  @message_class.decode(msg)
         
     | 
| 
       96 
111 
     | 
    
         
             
                end
         
     | 
| 
       97 
112 
     | 
    
         | 
| 
       98 
113 
     | 
    
         
             
                def on_readable(socket, messages)
         
     | 
| 
         @@ -102,7 +117,7 @@ class DripDrop 
     | 
|
| 
       102 
117 
     | 
    
         
             
                  when :dripdrop
         
     | 
| 
       103 
118 
     | 
    
         
             
                    raise "Expected message in one part" if messages.length > 1
         
     | 
| 
       104 
119 
     | 
    
         
             
                    body  = messages.shift.copy_out_string
         
     | 
| 
       105 
     | 
    
         
            -
                    @recv_cbak.call( 
     | 
| 
      
 120 
     | 
    
         
            +
                    @recv_cbak.call(decode_message(body))
         
     | 
| 
       106 
121 
     | 
    
         
             
                  else
         
     | 
| 
       107 
122 
     | 
    
         
             
                    raise "Unknown message format '#{@msg_format}'"
         
     | 
| 
       108 
123 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -129,7 +144,7 @@ class DripDrop 
     | 
|
| 
       129 
144 
     | 
    
         
             
                    topic = messages.shift.copy_out_string
         
     | 
| 
       130 
145 
     | 
    
         
             
                    if @topic_filter.nil? || topic.match(@topic_filter)
         
     | 
| 
       131 
146 
     | 
    
         
             
                      body  = messages.shift.copy_out_string
         
     | 
| 
       132 
     | 
    
         
            -
                      msg   = @recv_cbak.call( 
     | 
| 
      
 147 
     | 
    
         
            +
                      msg   = @recv_cbak.call(decode_message(body))
         
     | 
| 
       133 
148 
     | 
    
         
             
                    end
         
     | 
| 
       134 
149 
     | 
    
         
             
                  else
         
     | 
| 
       135 
150 
     | 
    
         
             
                    super(socket,messages)
         
     | 
| 
         @@ -173,15 +188,15 @@ class DripDrop 
     | 
|
| 
       173 
188 
     | 
    
         
             
                  if @msg_format == :dripdrop
         
     | 
| 
       174 
189 
     | 
    
         
             
                    identities = messages[0..-2].map {|m| m.copy_out_string}
         
     | 
| 
       175 
190 
     | 
    
         
             
                    body  = messages.last.copy_out_string
         
     | 
| 
       176 
     | 
    
         
            -
                    message =  
     | 
| 
      
 191 
     | 
    
         
            +
                    message = decode_message(body)
         
     | 
| 
       177 
192 
     | 
    
         
             
                    seq     = message.head['_dripdrop/x_seq_counter']
         
     | 
| 
       178 
     | 
    
         
            -
                    @recv_cbak.call(identities,seq 
     | 
| 
      
 193 
     | 
    
         
            +
                    @recv_cbak.call(message,identities,seq)
         
     | 
| 
       179 
194 
     | 
    
         
             
                  else
         
     | 
| 
       180 
195 
     | 
    
         
             
                    super(socket,messages)
         
     | 
| 
       181 
196 
     | 
    
         
             
                  end
         
     | 
| 
       182 
197 
     | 
    
         
             
                end
         
     | 
| 
       183 
198 
     | 
    
         | 
| 
       184 
     | 
    
         
            -
                def send_message(identities,seq 
     | 
| 
      
 199 
     | 
    
         
            +
                def send_message(message,identities,seq)
         
     | 
| 
       185 
200 
     | 
    
         
             
                  if message.is_a?(DripDrop::Message)
         
     | 
| 
       186 
201 
     | 
    
         
             
                    message.head['_dripdrop/x_seq_counter'] = seq
         
     | 
| 
       187 
202 
     | 
    
         
             
                    super(identities + [message.encoded])
         
     | 
    
        data/lib/dripdrop/message.rb
    CHANGED
    
    | 
         @@ -3,61 +3,93 @@ require 'bert' 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require 'json'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            class DripDrop
         
     | 
| 
       6 
     | 
    
         
            -
              #DripDrop::Message messages are exchanged between all tiers in the architecture
         
     | 
| 
       7 
     | 
    
         
            -
              #A Message is composed of a name, head, and body, and should be restricted to types that
         
     | 
| 
       8 
     | 
    
         
            -
              #can be readily encoded to JSON 
     | 
| 
       9 
     | 
    
         
            -
              # 
     | 
| 
      
 6 
     | 
    
         
            +
              # DripDrop::Message messages are exchanged between all tiers in the architecture
         
     | 
| 
      
 7 
     | 
    
         
            +
              # A Message is composed of a name, head, and body, and should be restricted to types that
         
     | 
| 
      
 8 
     | 
    
         
            +
              # can be readily encoded to JSON.
         
     | 
| 
      
 9 
     | 
    
         
            +
              # name: Any string
         
     | 
| 
      
 10 
     | 
    
         
            +
              # head: A hash containing anything (should be used for metadata)
         
     | 
| 
      
 11 
     | 
    
         
            +
              # body: anything you'd like, it can be null even
         
     | 
| 
       10 
12 
     | 
    
         
             
              #
         
     | 
| 
       11 
     | 
    
         
            -
              # 
     | 
| 
       12 
     | 
    
         
            -
              # 
     | 
| 
       13 
     | 
    
         
            -
              # 
     | 
| 
       14 
     | 
    
         
            -
              # 
     | 
| 
      
 13 
     | 
    
         
            +
              # Hashes, arrays, strings, integers, symbols, and floats are probably what you should stick to.
         
     | 
| 
      
 14 
     | 
    
         
            +
              # Internally, they're just stored as BERT, which is great because if you don't use JSON
         
     | 
| 
      
 15 
     | 
    
         
            +
              # things like symbols and binary data are transmitted more efficiently and transparently.
         
     | 
| 
      
 16 
     | 
    
         
            +
              #
         
     | 
| 
      
 17 
     | 
    
         
            +
              # The basic message format is built to mimic HTTP (s/url_path/name/). Why? Because I'm a dumb web developer :)
         
     | 
| 
      
 18 
     | 
    
         
            +
              # The name is kind of like the URL, its what kind of message this is, but it's a loose definition,
         
     | 
| 
      
 19 
     | 
    
         
            +
              # use it as you see fit.
         
     | 
| 
      
 20 
     | 
    
         
            +
              # head should be used for metadata, body for the actual data.
         
     | 
| 
      
 21 
     | 
    
         
            +
              # These definitions are intentionally loose, because protocols tend to be used loosely.
         
     | 
| 
       15 
22 
     | 
    
         
             
              class Message
         
     | 
| 
       16 
23 
     | 
    
         
             
                attr_accessor :name, :head, :body
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                # 
     | 
| 
       19 
     | 
    
         
            -
                #example:
         
     | 
| 
       20 
     | 
    
         
            -
                # 
     | 
| 
       21 
     | 
    
         
            -
                # 
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                # Creates a new message.
         
     | 
| 
      
 26 
     | 
    
         
            +
                # example:
         
     | 
| 
      
 27 
     | 
    
         
            +
                #   DripDrop::Message.new('mymessage', :head => {:timestamp => Time.now},
         
     | 
| 
      
 28 
     | 
    
         
            +
                #     :body => {:mykey => :myval,  :other_key => ['complex']})
         
     | 
| 
       22 
29 
     | 
    
         
             
                def initialize(name,extra={})
         
     | 
| 
       23 
     | 
    
         
            -
                  raise " 
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 30 
     | 
    
         
            +
                  raise ArgumentError, "Message names may not be empty or null!" if name.nil? || name.empty?
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       25 
32 
     | 
    
         
             
                  @head = extra[:head] || {}
         
     | 
| 
       26 
     | 
    
         
            -
                  raise " 
     | 
| 
       27 
     | 
    
         
            -
                  
         
     | 
| 
      
 33 
     | 
    
         
            +
                  raise ArgumentError, "Invalid head #{@head}. Head must be a hash!" unless @head.is_a?(Hash)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @head[:msg_class] = self.class.to_s
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
       28 
36 
     | 
    
         
             
                  @name = name
         
     | 
| 
       29 
37 
     | 
    
         
             
                  @body = extra[:body]
         
     | 
| 
       30 
38 
     | 
    
         
             
                end
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                #The encoded message, ready to be sent across the wire via ZMQ
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                # The encoded message, ready to be sent across the wire via ZMQ
         
     | 
| 
       33 
41 
     | 
    
         
             
                def encoded
         
     | 
| 
       34 
42 
     | 
    
         
             
                  BERT.encode(self.to_hash)
         
     | 
| 
       35 
43 
     | 
    
         
             
                end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                 
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                # Encodes the hash represntation of the message to JSON
         
     | 
| 
      
 46 
     | 
    
         
            +
                def json_encoded
         
     | 
| 
       38 
47 
     | 
    
         
             
                  self.to_hash.to_json
         
     | 
| 
       39 
48 
     | 
    
         
             
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
                # (Deprecated, use json_encoded)
         
     | 
| 
      
 50 
     | 
    
         
            +
                def encode_json; json_encoded; end
         
     | 
| 
       40 
51 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                #Convert the Message to a hash like:
         
     | 
| 
       42 
     | 
    
         
            -
                #{:name => @name, :head => @head, :body => @body}
         
     | 
| 
      
 52 
     | 
    
         
            +
                # Convert the Message to a hash like:
         
     | 
| 
      
 53 
     | 
    
         
            +
                # {:name => @name, :head => @head, :body => @body}
         
     | 
| 
       43 
54 
     | 
    
         
             
                def to_hash
         
     | 
| 
       44 
55 
     | 
    
         
             
                  {:name => @name, :head => @head, :body => @body}
         
     | 
| 
       45 
56 
     | 
    
         
             
                end
         
     | 
| 
       46 
57 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
                # 
     | 
| 
       48 
     | 
    
         
            -
                 
     | 
| 
       49 
     | 
    
         
            -
                def self. 
     | 
| 
      
 58 
     | 
    
         
            +
                # Build a new Message from a hash that looks like
         
     | 
| 
      
 59 
     | 
    
         
            +
                #    {:name => name, :body => body, :head => head}
         
     | 
| 
      
 60 
     | 
    
         
            +
                def self.from_hash(hash)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  self.new(hash[:name],:head => hash[:head], :body => hash[:body])
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                def self.create_message(*args)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  case args[0]
         
     | 
| 
      
 66 
     | 
    
         
            +
                    when Hash then self.from_hash(args[0])
         
     | 
| 
      
 67 
     | 
    
         
            +
                    else self.new(args)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def self.recreate_message(hash)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  raise ArgumentError, "Wrong message class #{hash[:head][:msg_class]} for #{self.to_s}" unless hash[:head][:msg_class] == self.to_s
         
     | 
| 
      
 73 
     | 
    
         
            +
                  self.from_hash(hash)
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                # Parses an already encoded string
         
     | 
| 
      
 77 
     | 
    
         
            +
                def self.decode(msg)
         
     | 
| 
       50 
78 
     | 
    
         
             
                  return nil if msg.nil? || msg.empty?
         
     | 
| 
       51 
79 
     | 
    
         
             
                  #This makes parsing ZMQ messages less painful, even if its ugly here
         
     | 
| 
       52 
80 
     | 
    
         
             
                  #We check the class name as a string in case we don't have ZMQ loaded
         
     | 
| 
       53 
81 
     | 
    
         
             
                  if msg.class.to_s == 'ZMQ::Message'
         
     | 
| 
       54 
     | 
    
         
            -
                    msg = msg.copy_out_string 
     | 
| 
      
 82 
     | 
    
         
            +
                    msg = msg.copy_out_string
         
     | 
| 
       55 
83 
     | 
    
         
             
                    return nil if msg.empty?
         
     | 
| 
       56 
84 
     | 
    
         
             
                  end
         
     | 
| 
       57 
85 
     | 
    
         
             
                  decoded = BERT.decode(msg)
         
     | 
| 
       58 
     | 
    
         
            -
                  self. 
     | 
| 
      
 86 
     | 
    
         
            +
                  self.recreate_message(decoded)
         
     | 
| 
       59 
87 
     | 
    
         
             
                end
         
     | 
| 
       60 
88 
     | 
    
         | 
| 
      
 89 
     | 
    
         
            +
                # (Deprecated). Use decode instead
         
     | 
| 
      
 90 
     | 
    
         
            +
                def self.parse(msg); self.decode(msg) end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                # Decodes a string containing a JSON representation of a message
         
     | 
| 
       61 
93 
     | 
    
         
             
                def self.decode_json(str)
         
     | 
| 
       62 
94 
     | 
    
         
             
                  begin
         
     | 
| 
       63 
95 
     | 
    
         
             
                    json_hash = JSON.parse(str)
         
     | 
| 
         @@ -67,12 +99,57 @@ class DripDrop 
     | 
|
| 
       67 
99 
     | 
    
         
             
                  end
         
     | 
| 
       68 
100 
     | 
    
         
             
                  self.new(json_hash['name'], :head => json_hash['head'], :body => json_hash['body'])
         
     | 
| 
       69 
101 
     | 
    
         
             
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
              end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
              #Use of this "metaclass" allows for the automatic recognition of the message's
         
     | 
| 
      
 105 
     | 
    
         
            +
              #base class
         
     | 
| 
      
 106 
     | 
    
         
            +
              class AutoMessageClass < Message
         
     | 
| 
      
 107 
     | 
    
         
            +
                def initialize(*args)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  raise "Cannot create an instance of this class - please use create_message class method"
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 112 
     | 
    
         
            +
                  attr_accessor :message_subclasses
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  DripDrop::AutoMessageClass.message_subclasses = {'DripDrop::Message' => DripDrop::Message}
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  def verify_args(*args)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    head =
         
     | 
| 
      
 118 
     | 
    
         
            +
                      case args[0]
         
     | 
| 
      
 119 
     | 
    
         
            +
                        when Hash then args[0][:head]
         
     | 
| 
      
 120 
     | 
    
         
            +
                        else args[1]
         
     | 
| 
      
 121 
     | 
    
         
            +
                      end
         
     | 
| 
      
 122 
     | 
    
         
            +
                    raise ArgumentError, "Invalid head #{head}. Head must be a hash!" unless head.is_a?(Hash)
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                    msg_class = head[:msg_class]
         
     | 
| 
      
 125 
     | 
    
         
            +
                    unless DripDrop::AutoMessageClass.message_subclasses.has_key?(msg_class)
         
     | 
| 
      
 126 
     | 
    
         
            +
                      raise ArgumentError, "Unknown AutoMessage message class #{msg_class}"
         
     | 
| 
      
 127 
     | 
    
         
            +
                    end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                    DripDrop::AutoMessageClass.message_subclasses[msg_class]
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  def create_message(*args)
         
     | 
| 
      
 133 
     | 
    
         
            +
                    klass = verify_args(*args)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    klass.create_message(*args)
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                  def recreate_message(*args)
         
     | 
| 
      
 138 
     | 
    
         
            +
                    klass = verify_args(*args)
         
     | 
| 
      
 139 
     | 
    
         
            +
                    klass.recreate_message(*args)
         
     | 
| 
      
 140 
     | 
    
         
            +
                  end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                  def register_subclass(klass)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    DripDrop::AutoMessageClass.message_subclasses[klass.to_s] = klass
         
     | 
| 
      
 144 
     | 
    
         
            +
                  end
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
              end
         
     | 
| 
       70 
147 
     | 
    
         | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
                def  
     | 
| 
       75 
     | 
    
         
            -
                   
     | 
| 
      
 148 
     | 
    
         
            +
              #Including this module into your subclass will automatically register the class
         
     | 
| 
      
 149 
     | 
    
         
            +
              #with AutoMessageClass
         
     | 
| 
      
 150 
     | 
    
         
            +
              module SubclassedMessage
         
     | 
| 
      
 151 
     | 
    
         
            +
                def self.included(base)
         
     | 
| 
      
 152 
     | 
    
         
            +
                  DripDrop::AutoMessageClass.register_subclass base
         
     | 
| 
       76 
153 
     | 
    
         
             
                end
         
     | 
| 
       77 
154 
     | 
    
         
             
              end
         
     | 
| 
       78 
155 
     | 
    
         
             
            end
         
     | 
    
        data/lib/dripdrop/node.rb
    CHANGED
    
    | 
         @@ -24,6 +24,8 @@ class DripDrop 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  @thread = nil
         
     | 
| 
       25 
25 
     | 
    
         
             
                end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
                # Starts the reactors and runs the block passed to initialize.
         
     | 
| 
      
 28 
     | 
    
         
            +
                # This is non-blocking.
         
     | 
| 
       27 
29 
     | 
    
         
             
                def start
         
     | 
| 
       28 
30 
     | 
    
         
             
                  @thread = Thread.new do
         
     | 
| 
       29 
31 
     | 
    
         
             
                    EM.run do
         
     | 
| 
         @@ -35,6 +37,9 @@ class DripDrop 
     | 
|
| 
       35 
37 
     | 
    
         
             
                  end
         
     | 
| 
       36 
38 
     | 
    
         
             
                end
         
     | 
| 
       37 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
                # If the reactor has started, this blocks until the thread 
         
     | 
| 
      
 41 
     | 
    
         
            +
                # running the reactor joins. This should block forever
         
     | 
| 
      
 42 
     | 
    
         
            +
                # unless +stop+ is called.
         
     | 
| 
       38 
43 
     | 
    
         
             
                def join
         
     | 
| 
       39 
44 
     | 
    
         
             
                  if @thread
         
     | 
| 
       40 
45 
     | 
    
         
             
                    @thread.join
         
     | 
| 
         @@ -43,55 +48,38 @@ class DripDrop 
     | 
|
| 
       43 
48 
     | 
    
         
             
                  end
         
     | 
| 
       44 
49 
     | 
    
         
             
                end
         
     | 
| 
       45 
50 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
                #Blocking version of start, equivalent to +start+ then +join+
         
     | 
| 
      
 51 
     | 
    
         
            +
                # Blocking version of start, equivalent to +start+ then +join+
         
     | 
| 
       47 
52 
     | 
    
         
             
                def start!
         
     | 
| 
       48 
53 
     | 
    
         
             
                  self.start
         
     | 
| 
       49 
54 
     | 
    
         
             
                  self.join
         
     | 
| 
       50 
55 
     | 
    
         
             
                end
         
     | 
| 
       51 
56 
     | 
    
         | 
| 
      
 57 
     | 
    
         
            +
                # Stops the reactors. If you were blocked on #join, that will unblock.
         
     | 
| 
       52 
58 
     | 
    
         
             
                def stop
         
     | 
| 
       53 
59 
     | 
    
         
             
                  @zm_reactor.stop
         
     | 
| 
       54 
60 
     | 
    
         
             
                  EM.stop
         
     | 
| 
       55 
61 
     | 
    
         
             
                end
         
     | 
| 
       56 
62 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
                #TODO: All these need to be majorly DRYed up
         
     | 
| 
       58 
     | 
    
         
            -
                 
         
     | 
| 
       59 
63 
     | 
    
         
             
                # Creates a ZMQ::SUB type socket. Can only receive messages via +on_recv+
         
     | 
| 
       60 
64 
     | 
    
         
             
                def zmq_subscribe(address,socket_ctype,opts={},&block)
         
     | 
| 
       61 
     | 
    
         
            -
                   
     | 
| 
       62 
     | 
    
         
            -
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
       63 
     | 
    
         
            -
                  handler = DripDrop::ZMQSubHandler.new(zm_addr,@zm_reactor,socket_ctype,h_opts)
         
     | 
| 
       64 
     | 
    
         
            -
                  @zm_reactor.sub_socket(handler)
         
     | 
| 
       65 
     | 
    
         
            -
                  handler
         
     | 
| 
      
 65 
     | 
    
         
            +
                  zmq_handler(DripDrop::ZMQSubHandler,:sub_socket,address,socket_ctype,opts={})
         
     | 
| 
       66 
66 
     | 
    
         
             
                end
         
     | 
| 
       67 
67 
     | 
    
         | 
| 
       68 
68 
     | 
    
         
             
                # Creates a ZMQ::PUB type socket, can only send messages via +send_message+
         
     | 
| 
       69 
69 
     | 
    
         
             
                def zmq_publish(address,socket_ctype,opts={})
         
     | 
| 
       70 
     | 
    
         
            -
                   
     | 
| 
       71 
     | 
    
         
            -
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
       72 
     | 
    
         
            -
                  handler = DripDrop::ZMQPubHandler.new(zm_addr,@zm_reactor,socket_ctype,h_opts)
         
     | 
| 
       73 
     | 
    
         
            -
                  @zm_reactor.pub_socket(handler)
         
     | 
| 
       74 
     | 
    
         
            -
                  handler
         
     | 
| 
      
 70 
     | 
    
         
            +
                  zmq_handler(DripDrop::ZMQPubHandler,:pub_socket,address,socket_ctype,opts={})
         
     | 
| 
       75 
71 
     | 
    
         
             
                end
         
     | 
| 
       76 
72 
     | 
    
         | 
| 
       77 
73 
     | 
    
         
             
                # Creates a ZMQ::PULL type socket. Can only receive messages via +on_recv+
         
     | 
| 
       78 
74 
     | 
    
         
             
                def zmq_pull(address,socket_ctype,opts={},&block)
         
     | 
| 
       79 
     | 
    
         
            -
                   
     | 
| 
       80 
     | 
    
         
            -
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
       81 
     | 
    
         
            -
                  handler = DripDrop::ZMQPullHandler.new(zm_addr,@zm_reactor,socket_ctype,h_opts)
         
     | 
| 
       82 
     | 
    
         
            -
                  @zm_reactor.pull_socket(handler)
         
     | 
| 
       83 
     | 
    
         
            -
                  handler
         
     | 
| 
      
 75 
     | 
    
         
            +
                  zmq_handler(DripDrop::ZMQPullHandler,:pull_socket,address,socket_ctype,opts={})
         
     | 
| 
       84 
76 
     | 
    
         
             
                end
         
     | 
| 
       85 
77 
     | 
    
         | 
| 
       86 
78 
     | 
    
         
             
                # Creates a ZMQ::PUSH type socket, can only send messages via +send_message+
         
     | 
| 
       87 
79 
     | 
    
         
             
                def zmq_push(address,socket_ctype,opts={})
         
     | 
| 
       88 
     | 
    
         
            -
                   
     | 
| 
       89 
     | 
    
         
            -
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
       90 
     | 
    
         
            -
                  handler = DripDrop::ZMQPushHandler.new(zm_addr,@zm_reactor,socket_ctype,h_opts)
         
     | 
| 
       91 
     | 
    
         
            -
                  @zm_reactor.push_socket(handler)
         
     | 
| 
       92 
     | 
    
         
            -
                  handler
         
     | 
| 
      
 80 
     | 
    
         
            +
                  zmq_handler(DripDrop::ZMQPushHandler,:push_socket,address,socket_ctype,opts={})
         
     | 
| 
       93 
81 
     | 
    
         
             
                end
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
       95 
83 
     | 
    
         
             
                # Creates a ZMQ::XREP type socket, both sends and receivesc XREP sockets are extremely
         
     | 
| 
       96 
84 
     | 
    
         
             
                # powerful, so their functionality is currently limited. XREP sockets in DripDrop can reply
         
     | 
| 
       97 
85 
     | 
    
         
             
                # to the original source of the message.
         
     | 
| 
         @@ -104,29 +92,32 @@ class DripDrop 
     | 
|
| 
       104 
92 
     | 
    
         
             
                # To reply from an xrep handler, be sure to call send messages with the same +identities+ and +seq+
         
     | 
| 
       105 
93 
     | 
    
         
             
                # arguments that +on_recv+ had. So, send_message takes +identities+, +seq+, and +message+.
         
     | 
| 
       106 
94 
     | 
    
         
             
                def zmq_xrep(address,socket_ctype,opts={})
         
     | 
| 
       107 
     | 
    
         
            -
                   
     | 
| 
       108 
     | 
    
         
            -
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
       109 
     | 
    
         
            -
                  handler = DripDrop::ZMQXRepHandler.new(zm_addr,@zm_reactor,socket_ctype,h_opts)
         
     | 
| 
       110 
     | 
    
         
            -
                  @zm_reactor.xrep_socket(handler)
         
     | 
| 
       111 
     | 
    
         
            -
                  handler
         
     | 
| 
      
 95 
     | 
    
         
            +
                  zmq_handler(DripDrop::ZMQXRepHandler,:xrep_socket,address,socket_ctype,opts={})
         
     | 
| 
       112 
96 
     | 
    
         
             
                end
         
     | 
| 
       113 
97 
     | 
    
         | 
| 
       114 
98 
     | 
    
         
             
                # See the documentation for +zmq_xrep+ for more info
         
     | 
| 
       115 
99 
     | 
    
         
             
                def zmq_xreq(address,socket_ctype,opts={})
         
     | 
| 
       116 
     | 
    
         
            -
                   
     | 
| 
       117 
     | 
    
         
            -
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
       118 
     | 
    
         
            -
                  handler = DripDrop::ZMQXReqHandler.new(zm_addr,@zm_reactor,socket_ctype,h_opts)
         
     | 
| 
       119 
     | 
    
         
            -
                  @zm_reactor.xreq_socket(handler)
         
     | 
| 
       120 
     | 
    
         
            -
                  handler
         
     | 
| 
      
 100 
     | 
    
         
            +
                  zmq_handler(DripDrop::ZMQXReqHandler,:xreq_socket,address,socket_ctype,opts={})
         
     | 
| 
       121 
101 
     | 
    
         
             
                end
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
                 
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                # Binds an EM websocket connection to +address+. takes blocks for
         
     | 
| 
      
 104 
     | 
    
         
            +
                # +on_open+, +on_recv+, +on_close+ and +on_error+.
         
     | 
| 
      
 105 
     | 
    
         
            +
                #
         
     | 
| 
      
 106 
     | 
    
         
            +
                # For example +on_recv+ could be used to echo incoming messages thusly:
         
     | 
| 
      
 107 
     | 
    
         
            +
                #    websocket(addr).on_recv {|msg,websocket| ws.send(msg)}
         
     | 
| 
      
 108 
     | 
    
         
            +
                #
         
     | 
| 
      
 109 
     | 
    
         
            +
                # All other events only receive the +websocket+ object, which corresponds
         
     | 
| 
      
 110 
     | 
    
         
            +
                # not to the +DripDrop::WebSocketHandler+ object, but to an em-websocket object.
         
     | 
| 
      
 111 
     | 
    
         
            +
                def websocket(address,opts={})
         
     | 
| 
       124 
112 
     | 
    
         
             
                  uri     = URI.parse(address)
         
     | 
| 
       125 
113 
     | 
    
         
             
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
       126 
114 
     | 
    
         
             
                  handler = DripDrop::WebSocketHandler.new(uri,h_opts)
         
     | 
| 
       127 
115 
     | 
    
         
             
                  handler
         
     | 
| 
       128 
116 
     | 
    
         
             
                end
         
     | 
| 
       129 
117 
     | 
    
         | 
| 
      
 118 
     | 
    
         
            +
                # Starts a new Thin HTTP server listening on address.
         
     | 
| 
      
 119 
     | 
    
         
            +
                # Can have an +on_recv+ handler that gets passed a single +response+ arg.
         
     | 
| 
      
 120 
     | 
    
         
            +
                #    http_server(addr) {|response,msg| response.send_message(msg)}
         
     | 
| 
       130 
121 
     | 
    
         
             
                def http_server(address,opts={},&block)
         
     | 
| 
       131 
122 
     | 
    
         
             
                  uri     = URI.parse(address)
         
     | 
| 
       132 
123 
     | 
    
         
             
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
         @@ -134,6 +125,12 @@ class DripDrop 
     | 
|
| 
       134 
125 
     | 
    
         
             
                  handler
         
     | 
| 
       135 
126 
     | 
    
         
             
                end
         
     | 
| 
       136 
127 
     | 
    
         | 
| 
      
 128 
     | 
    
         
            +
                # An EM HTTP client.
         
     | 
| 
      
 129 
     | 
    
         
            +
                # Example:
         
     | 
| 
      
 130 
     | 
    
         
            +
                #    client = http_client(addr)
         
     | 
| 
      
 131 
     | 
    
         
            +
                #    client.send_message(:name => 'name', :body => 'hi') do |resp_msg|
         
     | 
| 
      
 132 
     | 
    
         
            +
                #      puts resp_msg.inspect
         
     | 
| 
      
 133 
     | 
    
         
            +
                #    end
         
     | 
| 
       137 
134 
     | 
    
         
             
                def http_client(address,opts={})
         
     | 
| 
       138 
135 
     | 
    
         
             
                  uri     = URI.parse(address)
         
     | 
| 
       139 
136 
     | 
    
         
             
                  h_opts  = handler_opts_given(opts)
         
     | 
| 
         @@ -141,6 +138,15 @@ class DripDrop 
     | 
|
| 
       141 
138 
     | 
    
         
             
                  handler
         
     | 
| 
       142 
139 
     | 
    
         
             
                end
         
     | 
| 
       143 
140 
     | 
    
         | 
| 
      
 141 
     | 
    
         
            +
                # An inprocess pub/sub queue that works similarly to EM::Channel, 
         
     | 
| 
      
 142 
     | 
    
         
            +
                # but has manually specified identifiers for subscribers letting you
         
     | 
| 
      
 143 
     | 
    
         
            +
                # more easily delete subscribers without crazy id tracking.
         
     | 
| 
      
 144 
     | 
    
         
            +
                #  
         
     | 
| 
      
 145 
     | 
    
         
            +
                # This is useful for situations where you want to broadcast messages across your app,
         
     | 
| 
      
 146 
     | 
    
         
            +
                # but need a way to properly delete listeners.
         
     | 
| 
      
 147 
     | 
    
         
            +
                # 
         
     | 
| 
      
 148 
     | 
    
         
            +
                # +dest+ is the name of the pub/sub channel.
         
     | 
| 
      
 149 
     | 
    
         
            +
                # +data+ is any type of ruby var you'd like to send.
         
     | 
| 
       144 
150 
     | 
    
         
             
                def send_internal(dest,data)
         
     | 
| 
       145 
151 
     | 
    
         
             
                  return false unless @recipients_for[dest]
         
     | 
| 
       146 
152 
     | 
    
         
             
                  blocks = @recipients_for[dest].values
         
     | 
| 
         @@ -150,6 +156,9 @@ class DripDrop 
     | 
|
| 
       150 
156 
     | 
    
         
             
                  end
         
     | 
| 
       151 
157 
     | 
    
         
             
                end
         
     | 
| 
       152 
158 
     | 
    
         | 
| 
      
 159 
     | 
    
         
            +
                # Defines a subscriber to the channel +dest+, to receive messages from +send_internal+.
         
     | 
| 
      
 160 
     | 
    
         
            +
                # +identifier+ is a unique identifier for this receiver.
         
     | 
| 
      
 161 
     | 
    
         
            +
                # The identifier can be used by +remove_recv_internal+ 
         
     | 
| 
       153 
162 
     | 
    
         
             
                def recv_internal(dest,identifier,&block)
         
     | 
| 
       154 
163 
     | 
    
         
             
                  if @recipients_for[dest]
         
     | 
| 
       155 
164 
     | 
    
         
             
                    @recipients_for[dest][identifier] =  block
         
     | 
| 
         @@ -158,6 +167,8 @@ class DripDrop 
     | 
|
| 
       158 
167 
     | 
    
         
             
                  end
         
     | 
| 
       159 
168 
     | 
    
         
             
                end
         
     | 
| 
       160 
169 
     | 
    
         | 
| 
      
 170 
     | 
    
         
            +
                # Deletes a subscriber to the channel +dest+ previously identified by a
         
     | 
| 
      
 171 
     | 
    
         
            +
                # reciever created with +recv_internal+
         
     | 
| 
       161 
172 
     | 
    
         
             
                def remove_recv_internal(dest,identifier)
         
     | 
| 
       162 
173 
     | 
    
         
             
                  return false unless @recipients_for[dest]
         
     | 
| 
       163 
174 
     | 
    
         
             
                  @recipients_for[dest].delete(identifier)
         
     | 
| 
         @@ -165,10 +176,14 @@ class DripDrop 
     | 
|
| 
       165 
176 
     | 
    
         | 
| 
       166 
177 
     | 
    
         
             
                private
         
     | 
| 
       167 
178 
     | 
    
         | 
| 
       168 
     | 
    
         
            -
                def  
     | 
| 
       169 
     | 
    
         
            -
                  addr_uri = URI.parse( 
     | 
| 
       170 
     | 
    
         
            -
                  ZM::Address.new(addr_uri.host,addr_uri.port.to_i,addr_uri.scheme.to_sym)
         
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
      
 179 
     | 
    
         
            +
                def zmq_handler(klass, zm_sock_type, address, socket_ctype, opts={})
         
     | 
| 
      
 180 
     | 
    
         
            +
                  addr_uri = URI.parse(address)
         
     | 
| 
      
 181 
     | 
    
         
            +
                  zm_addr  = ZM::Address.new(addr_uri.host,addr_uri.port.to_i,addr_uri.scheme.to_sym)
         
     | 
| 
      
 182 
     | 
    
         
            +
                  h_opts   = handler_opts_given(opts)
         
     | 
| 
      
 183 
     | 
    
         
            +
                  handler  = klass.new(zm_addr,@zm_reactor,socket_ctype,h_opts)
         
     | 
| 
      
 184 
     | 
    
         
            +
                  @zm_reactor.send(zm_sock_type,handler)
         
     | 
| 
      
 185 
     | 
    
         
            +
                  handler
         
     | 
| 
      
 186 
     | 
    
         
            +
                end   
         
     | 
| 
       172 
187 
     | 
    
         | 
| 
       173 
188 
     | 
    
         
             
                def handler_opts_given(opts)
         
     | 
| 
       174 
189 
     | 
    
         
             
                  @handler_default_opts.merge(opts)
         
     | 
    
        data/lib/dripdrop.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,99 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class SpecMessageClass < DripDrop::Message
         
     | 
| 
      
 4 
     | 
    
         
            +
              include DripDrop::SubclassedMessage
         
     | 
| 
      
 5 
     | 
    
         
            +
            end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            describe DripDrop::Message do
         
     | 
| 
      
 8 
     | 
    
         
            +
              describe "basic message" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                def create_basic
         
     | 
| 
      
 10 
     | 
    
         
            +
                  attrs = {
         
     | 
| 
      
 11 
     | 
    
         
            +
                    :name => 'test',
         
     | 
| 
      
 12 
     | 
    
         
            +
                    :head => {:foo => :bar},
         
     | 
| 
      
 13 
     | 
    
         
            +
                    :body => [:foo, :bar, :baz]
         
     | 
| 
      
 14 
     | 
    
         
            +
                  }
         
     | 
| 
      
 15 
     | 
    
         
            +
                  message = DripDrop::Message.new(attrs[:name],:head => attrs[:head],
         
     | 
| 
      
 16 
     | 
    
         
            +
                                                               :body => attrs[:body])
         
     | 
| 
      
 17 
     | 
    
         
            +
                  [message, attrs]
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
                it "should create a basic message without raising an exception" do
         
     | 
| 
      
 20 
     | 
    
         
            +
                  lambda {
         
     | 
| 
      
 21 
     | 
    
         
            +
                    message, attrs = create_basic
         
     | 
| 
      
 22 
     | 
    
         
            +
                  }.should_not raise_exception
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
                describe "with minimal attributes" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                  it "should create a message with only a name" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                    lambda {
         
     | 
| 
      
 27 
     | 
    
         
            +
                      DripDrop::Message.new('nameonly')
         
     | 
| 
      
 28 
     | 
    
         
            +
                    }.should_not raise_exception
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  it "should set the head to a single key hash containing message class if nil provided" do
         
     | 
| 
      
 31 
     | 
    
         
            +
                    DripDrop::Message.new('nilhead', :head => nil).head.should == {:msg_class => 'DripDrop::Message'}
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  it "should raise an exception if a non-hash, non-nil head is provided" do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    lambda {
         
     | 
| 
      
 35 
     | 
    
         
            +
                      DripDrop::Message.new('arrhead', :head => [])
         
     | 
| 
      
 36 
     | 
    
         
            +
                    }.should raise_exception(ArgumentError)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
                describe "encoding" do
         
     | 
| 
      
 40 
     | 
    
         
            +
                  before(:all) do
         
     | 
| 
      
 41 
     | 
    
         
            +
                    @message, @attrs = create_basic
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  it "should encode to valid BERT hash without error" do
         
     | 
| 
      
 44 
     | 
    
         
            +
                    enc = @message.encoded
         
     | 
| 
      
 45 
     | 
    
         
            +
                    enc.should be_a(String)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    BERT.decode(enc).should be_a(Hash)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  it "should decode encoded messages without errors" do
         
     | 
| 
      
 49 
     | 
    
         
            +
                    DripDrop::Message.decode(@message.encoded).should be_a(DripDrop::Message)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  it "should encode to valid JSON without error" do
         
     | 
| 
      
 52 
     | 
    
         
            +
                    enc = @message.json_encoded
         
     | 
| 
      
 53 
     | 
    
         
            +
                    enc.should be_a(String)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    JSON.parse(enc).should be_a(Hash)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  it "should decode JSON encoded messages without errors" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                    DripDrop::Message.decode_json(@message.json_encoded).should be_a(DripDrop::Message)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                  it "should convert messages to Hash representations" do
         
     | 
| 
      
 60 
     | 
    
         
            +
                    @message.to_hash.should be_a(Hash)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
                  it "should be able to turn hash representations back into Message objs" do
         
     | 
| 
      
 63 
     | 
    
         
            +
                    DripDrop::Message.from_hash(@message.to_hash).should be_a(DripDrop::Message)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
                describe "subclassing" do
         
     | 
| 
      
 67 
     | 
    
         
            +
                  def create_auto_message
         
     | 
| 
      
 68 
     | 
    
         
            +
                    attrs = {
         
     | 
| 
      
 69 
     | 
    
         
            +
                      :name => 'test',
         
     | 
| 
      
 70 
     | 
    
         
            +
                      :head => {:foo => :bar, :msg_class => 'SpecMessageClass'},
         
     | 
| 
      
 71 
     | 
    
         
            +
                      :body => [:foo, :bar, :baz]
         
     | 
| 
      
 72 
     | 
    
         
            +
                    }
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    message = DripDrop::AutoMessageClass.create_message(attrs)
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    [message, attrs]
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                  before(:all) do
         
     | 
| 
      
 79 
     | 
    
         
            +
                    @message, @attrs = create_auto_message
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  it "should be added to the subclass message class hash if SubclassedMessage included" do
         
     | 
| 
      
 82 
     | 
    
         
            +
                    DripDrop::AutoMessageClass.message_subclasses.should include('SpecMessageClass' => SpecMessageClass)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                  it "should throw an exception if we try to recreate a message of the wrong class" do
         
     | 
| 
      
 85 
     | 
    
         
            +
                    msg = DripDrop::Message.new('test')
         
     | 
| 
      
 86 
     | 
    
         
            +
                    lambda{SpecMessageClass.recreate_message(msg.to_hash)}.should raise_exception
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  describe "DripDrop::AutoMessageClass" do
         
     | 
| 
      
 90 
     | 
    
         
            +
                    it "should create a properly classed message based on head[:msg_class]" do
         
     | 
| 
      
 91 
     | 
    
         
            +
                      @message.should be_a(SpecMessageClass)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    end
         
     | 
| 
      
 93 
     | 
    
         
            +
                    it "should recreate a message based on head[:msg_class]" do
         
     | 
| 
      
 94 
     | 
    
         
            +
                      DripDrop::AutoMessageClass.recreate_message(@message.to_hash).should be_a(SpecMessageClass)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    end
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe "http" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              def http_send_messages(to_send,&block)
         
     | 
| 
      
 5 
     | 
    
         
            +
                responses = []
         
     | 
| 
      
 6 
     | 
    
         
            +
                client = nil
         
     | 
| 
      
 7 
     | 
    
         
            +
                server = nil
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                @ddn = DripDrop::Node.new do
         
     | 
| 
      
 10 
     | 
    
         
            +
                  addr = rand_addr
         
     | 
| 
      
 11 
     | 
    
         
            +
                  
         
     | 
| 
      
 12 
     | 
    
         
            +
                  zmq_subscribe(rand_addr, :bind) do |message|
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  
         
     | 
| 
      
 15 
     | 
    
         
            +
                  client = http_client(addr)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  
         
     | 
| 
      
 17 
     | 
    
         
            +
                  server = http_server(addr).on_recv do |message,response|
         
     | 
| 
      
 18 
     | 
    
         
            +
                    $stdout.flush
         
     | 
| 
      
 19 
     | 
    
         
            +
                    responses << message
         
     | 
| 
      
 20 
     | 
    
         
            +
                    response.send_message(message)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  
         
     | 
| 
      
 23 
     | 
    
         
            +
                  to_send.each do |message|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    EM::next_tick do
         
     | 
| 
      
 25 
     | 
    
         
            +
                      http_client(addr).send_message(message) do |resp_message|
         
     | 
| 
      
 26 
     | 
    
         
            +
                        block.call(message,resp_message)
         
     | 
| 
      
 27 
     | 
    
         
            +
                      end
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
                @ddn.start
         
     | 
| 
      
 33 
     | 
    
         
            +
                sleep 0.1
         
     | 
| 
      
 34 
     | 
    
         
            +
                @ddn.stop
         
     | 
| 
      
 35 
     | 
    
         
            +
                
         
     | 
| 
      
 36 
     | 
    
         
            +
                {:responses => responses, :handlers => {:server => [server] }}
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
              describe "basic sending and receiving" do
         
     | 
| 
      
 39 
     | 
    
         
            +
                before(:all) do
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @sent = []
         
     | 
| 
      
 41 
     | 
    
         
            +
                  10.times {|i| @sent << DripDrop::Message.new("test-#{i}")}
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @client_responses = []
         
     | 
| 
      
 43 
     | 
    
         
            +
                  http_info = http_send_messages(@sent) do |sent_message,resp_message|
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @client_responses << {:sent_message  => sent_message,
         
     | 
| 
      
 45 
     | 
    
         
            +
                                          :resp_message  => resp_message}
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @responses     = http_info[:responses]
         
     | 
| 
      
 48 
     | 
    
         
            +
                  @push_handler  = http_info[:handlers][:push]
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @pull_handlers = http_info[:handlers][:pull]
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                it "should receive all sent messages" do
         
     | 
| 
      
 53 
     | 
    
         
            +
                  resp_names = @responses.map(&:name).inject(Set.new) {|memo,rn| memo << rn}
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @sent.map(&:name).each {|sn| resp_names.should include(sn)}
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
                
         
     | 
| 
      
 57 
     | 
    
         
            +
                it "should return to the client as many responses as sent messages" do
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @client_responses.length.should == @sent.length
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
                
         
     | 
| 
      
 61 
     | 
    
         
            +
                it "should return to the client an identical message to that which was sent" do
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @client_responses.each do |resp|
         
     | 
| 
      
 63 
     | 
    
         
            +
                    resp[:sent_message].name.should == resp[:resp_message].name
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -29,7 +29,7 @@ describe "zmq push/pull" do 
     | 
|
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                @ddn.start
         
     | 
| 
       31 
31 
     | 
    
         
             
                sleep 0.1
         
     | 
| 
       32 
     | 
    
         
            -
                @ddn.stop
         
     | 
| 
      
 32 
     | 
    
         
            +
                @ddn.stop rescue nil
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
                {:responses => responses, :handlers => { :push => push, :pull => [pull] }}
         
     | 
| 
       35 
35 
     | 
    
         
             
              end
         
     | 
| 
         @@ -43,10 +43,9 @@ describe "zmq push/pull" do 
     | 
|
| 
       43 
43 
     | 
    
         
             
                  @pull_handlers = pp_info[:handlers][:pull]
         
     | 
| 
       44 
44 
     | 
    
         
             
                end
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
                it "should receive all sent messages 
     | 
| 
       47 
     | 
    
         
            -
                  @ 
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                it "should receive all sent messages" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                  resp_names = @responses.map(&:name).inject(Set.new) {|memo,rn| memo << rn}
         
     | 
| 
      
 48 
     | 
    
         
            +
                  @sent.map(&:name).each {|sn| resp_names.should include(sn)}
         
     | 
| 
       50 
49 
     | 
    
         
             
                end
         
     | 
| 
       51 
50 
     | 
    
         | 
| 
       52 
51 
     | 
    
         
             
                it "should receive messages on both pull sockets" do
         
     | 
| 
         @@ -12,7 +12,7 @@ describe "zmq xreq/xrep" do 
     | 
|
| 
       12 
12 
     | 
    
         
             
                  rep = zmq_xrep(addr, :bind)
         
     | 
| 
       13 
13 
     | 
    
         
             
                  req = zmq_xreq(addr, :connect)
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                  rep.on_recv do |identities,seq 
     | 
| 
      
 15 
     | 
    
         
            +
                  rep.on_recv do |message,identities,seq|
         
     | 
| 
       16 
16 
     | 
    
         
             
                    yield(identities,seq,message) if block
         
     | 
| 
       17 
17 
     | 
    
         
             
                    responses << {:identities => identities, :seq => seq, :message => message}
         
     | 
| 
       18 
18 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -22,7 +22,7 @@ describe "zmq xreq/xrep" do 
     | 
|
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                @ddn.start
         
     | 
| 
       24 
24 
     | 
    
         
             
                sleep 0.1
         
     | 
| 
       25 
     | 
    
         
            -
                @ddn.stop
         
     | 
| 
      
 25 
     | 
    
         
            +
                @ddn.stop rescue nil
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                {:responses => responses, :handlers => {:req => req, :rep => rep}}
         
     | 
| 
       28 
28 
     | 
    
         
             
              end
         
     | 
| 
         @@ -64,8 +64,8 @@ describe "zmq xreq/xrep" do 
     | 
|
| 
       64 
64 
     | 
    
         
             
                    req1 = zmq_xreq(addr, :connect)
         
     | 
| 
       65 
65 
     | 
    
         
             
                    req2 = zmq_xreq(addr, :connect)
         
     | 
| 
       66 
66 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
                    rep.on_recv do |identities,seq 
     | 
| 
       68 
     | 
    
         
            -
                      rep.send_message(identities,seq 
     | 
| 
      
 67 
     | 
    
         
            +
                    rep.on_recv do |message,identities,seq|
         
     | 
| 
      
 68 
     | 
    
         
            +
                      rep.send_message(message,identities,seq)
         
     | 
| 
       69 
69 
     | 
    
         
             
                    end
         
     | 
| 
       70 
70 
     | 
    
         | 
| 
       71 
71 
     | 
    
         
             
                    r1_msg = DripDrop::Message.new("REQ1 Message")
         
     | 
    
        data/spec/node_spec.rb
    CHANGED
    
    | 
         @@ -2,17 +2,21 @@ require 'spec_helper' 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            describe DripDrop::Node do
         
     | 
| 
       4 
4 
     | 
    
         
             
              describe "initialization" do
         
     | 
| 
       5 
     | 
    
         
            -
                before do
         
     | 
| 
       6 
     | 
    
         
            -
                  @ddn = DripDrop::Node.new { 
     | 
| 
      
 5 
     | 
    
         
            +
                before(:all) do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @ddn = DripDrop::Node.new {
         
     | 
| 
      
 7 
     | 
    
         
            +
                    zmq_subscribe(rand_addr,:bind) #Keeps ZMQMachine Happy
         
     | 
| 
      
 8 
     | 
    
         
            +
                  }
         
     | 
| 
       7 
9 
     | 
    
         
             
                  @ddn.start
         
     | 
| 
       8 
     | 
    
         
            -
                  sleep  
     | 
| 
      
 10 
     | 
    
         
            +
                  sleep 1
         
     | 
| 
       9 
11 
     | 
    
         
             
                end
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
                it "should start EventMachine" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  pending "This is not repeatedly reliable"
         
     | 
| 
       12 
15 
     | 
    
         
             
                  EM.reactor_running?.should be_true
         
     | 
| 
       13 
16 
     | 
    
         
             
                end
         
     | 
| 
       14 
17 
     | 
    
         | 
| 
       15 
18 
     | 
    
         
             
                it "should start ZMQMachine" do
         
     | 
| 
      
 19 
     | 
    
         
            +
                  pending "This is not repeatedly reliable"
         
     | 
| 
       16 
20 
     | 
    
         
             
                  @ddn.zm_reactor.running?.should be_true
         
     | 
| 
       17 
21 
     | 
    
         
             
                end
         
     | 
| 
       18 
22 
     | 
    
         | 
| 
         @@ -23,10 +27,12 @@ describe DripDrop::Node do 
     | 
|
| 
       23 
27 
     | 
    
         | 
| 
       24 
28 
     | 
    
         
             
              describe "shutdown" do
         
     | 
| 
       25 
29 
     | 
    
         
             
                before do
         
     | 
| 
       26 
     | 
    
         
            -
                  @ddn = DripDrop::Node.new { 
     | 
| 
      
 30 
     | 
    
         
            +
                  @ddn = DripDrop::Node.new {
         
     | 
| 
      
 31 
     | 
    
         
            +
                    zmq_subscribe(rand_addr,:bind) #Keeps ZMQMachine Happy
         
     | 
| 
      
 32 
     | 
    
         
            +
                  }
         
     | 
| 
       27 
33 
     | 
    
         
             
                  @ddn.start
         
     | 
| 
       28 
     | 
    
         
            -
                  sleep 0.1 
     | 
| 
       29 
     | 
    
         
            -
                  @ddn.stop
         
     | 
| 
      
 34 
     | 
    
         
            +
                  sleep 0.1
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @ddn.stop rescue nil
         
     | 
| 
       30 
36 
     | 
    
         
             
                  sleep 0.1
         
     | 
| 
       31 
37 
     | 
    
         
             
                end
         
     | 
| 
       32 
38 
     | 
    
         | 
    
        metadata
    CHANGED
    
    | 
         @@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version 
     | 
|
| 
       4 
4 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       5 
5 
     | 
    
         
             
              segments: 
         
     | 
| 
       6 
6 
     | 
    
         
             
              - 0
         
     | 
| 
       7 
     | 
    
         
            -
              -  
     | 
| 
      
 7 
     | 
    
         
            +
              - 3
         
     | 
| 
       8 
8 
     | 
    
         
             
              - 0
         
     | 
| 
       9 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 9 
     | 
    
         
            +
              version: 0.3.0
         
     | 
| 
       10 
10 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       11 
11 
     | 
    
         
             
            authors: 
         
     | 
| 
       12 
12 
     | 
    
         
             
            - Andrew Cholakian
         
     | 
| 
         @@ -14,7 +14,7 @@ autorequire: 
     | 
|
| 
       14 
14 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       15 
15 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
            date: 2010-10- 
     | 
| 
      
 17 
     | 
    
         
            +
            date: 2010-10-21 00:00:00 -07:00
         
     | 
| 
       18 
18 
     | 
    
         
             
            default_executable: 
         
     | 
| 
       19 
19 
     | 
    
         
             
            dependencies: 
         
     | 
| 
       20 
20 
     | 
    
         
             
            - !ruby/object:Gem::Dependency 
         
     | 
| 
         @@ -91,6 +91,7 @@ files: 
     | 
|
| 
       91 
91 
     | 
    
         
             
            - example/http.rb
         
     | 
| 
       92 
92 
     | 
    
         
             
            - example/pubsub.rb
         
     | 
| 
       93 
93 
     | 
    
         
             
            - example/pushpull.rb
         
     | 
| 
      
 94 
     | 
    
         
            +
            - example/subclass.rb
         
     | 
| 
       94 
95 
     | 
    
         
             
            - example/xreq_xrep.rb
         
     | 
| 
       95 
96 
     | 
    
         
             
            - js/dripdrop.html
         
     | 
| 
       96 
97 
     | 
    
         
             
            - js/dripdrop.js
         
     | 
| 
         @@ -104,8 +105,10 @@ files: 
     | 
|
| 
       104 
105 
     | 
    
         
             
            - lib/dripdrop/handlers/zeromq.rb
         
     | 
| 
       105 
106 
     | 
    
         
             
            - lib/dripdrop/message.rb
         
     | 
| 
       106 
107 
     | 
    
         
             
            - lib/dripdrop/node.rb
         
     | 
| 
       107 
     | 
    
         
            -
            - spec/ 
     | 
| 
       108 
     | 
    
         
            -
            - spec/node/ 
     | 
| 
      
 108 
     | 
    
         
            +
            - spec/message_spec.rb
         
     | 
| 
      
 109 
     | 
    
         
            +
            - spec/node/http_spec.rb
         
     | 
| 
      
 110 
     | 
    
         
            +
            - spec/node/zmq_pushpull_spec.rb
         
     | 
| 
      
 111 
     | 
    
         
            +
            - spec/node/zmq_xrepxreq_spec.rb
         
     | 
| 
       109 
112 
     | 
    
         
             
            - spec/node_spec.rb
         
     | 
| 
       110 
113 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
       111 
114 
     | 
    
         
             
            has_rdoc: true
         
     | 
| 
         @@ -141,7 +144,9 @@ signing_key: 
     | 
|
| 
       141 
144 
     | 
    
         
             
            specification_version: 3
         
     | 
| 
       142 
145 
     | 
    
         
             
            summary: 0MQ App Stats
         
     | 
| 
       143 
146 
     | 
    
         
             
            test_files: 
         
     | 
| 
       144 
     | 
    
         
            -
            - spec/node/zmq_pushpull.rb
         
     | 
| 
       145 
     | 
    
         
            -
            - spec/node/zmq_xrepxreq.rb
         
     | 
| 
       146 
     | 
    
         
            -
            - spec/node_spec.rb
         
     | 
| 
       147 
147 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
      
 148 
     | 
    
         
            +
            - spec/node/http_spec.rb
         
     | 
| 
      
 149 
     | 
    
         
            +
            - spec/node/zmq_xrepxreq_spec.rb
         
     | 
| 
      
 150 
     | 
    
         
            +
            - spec/node/zmq_pushpull_spec.rb
         
     | 
| 
      
 151 
     | 
    
         
            +
            - spec/message_spec.rb
         
     | 
| 
      
 152 
     | 
    
         
            +
            - spec/node_spec.rb
         
     |