dripdrop 0.5.0 → 0.6.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 +2 -2
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/dripdrop.gemspec +12 -12
- data/example/subclass.rb +5 -5
- data/lib/dripdrop/agent.rb +0 -1
- data/lib/dripdrop/handlers/http.rb +1 -0
- data/lib/dripdrop/message.rb +25 -20
- data/spec/message_spec.rb +9 -14
- data/spec/node/http_spec.rb +2 -2
- data/spec/node/zmq_xrepxreq_spec.rb +2 -2
- metadata +11 -11
data/README.md
CHANGED
@@ -40,7 +40,7 @@ Here's an example of the kind of thing DripDrop makes easy, from [example/combin
|
|
40
40
|
end
|
41
41
|
end.start! #Start the reactor and block until complete
|
42
42
|
|
43
|
-
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
|
43
|
+
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 MessagePack. There is a raw mode 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.
|
44
44
|
|
45
45
|
#RDoc
|
46
46
|
|
@@ -48,7 +48,7 @@ RDocs can be found [here](http://www.rdoc.info/github/andrewvc/dripdrop/master/f
|
|
48
48
|
|
49
49
|
#How It Works
|
50
50
|
|
51
|
-
DripDrop encapsulates both zmqmachine, and eventmachine. It provides some sane default messaging choices, using [
|
51
|
+
DripDrop encapsulates both zmqmachine, and eventmachine. It provides some sane default messaging choices, using [MessagePack](http://msgpack.org/)(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.
|
52
52
|
|
53
53
|
#Contributors
|
54
54
|
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.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.6.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-
|
12
|
+
s.date = %q{2010-12-17}
|
13
13
|
s.description = %q{Evented framework for ZeroMQ and EventMachine Apps. }
|
14
14
|
s.email = %q{andrew@andrewvc.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -74,16 +74,16 @@ Gem::Specification.new do |s|
|
|
74
74
|
s.rubygems_version = %q{1.3.7}
|
75
75
|
s.summary = %q{Evented framework for ZeroMQ and EventMachine Apps.}
|
76
76
|
s.test_files = [
|
77
|
-
"spec/
|
78
|
-
"spec/
|
77
|
+
"spec/gimite-websocket.rb",
|
78
|
+
"spec/message_spec.rb",
|
79
|
+
"spec/node_spec.rb",
|
80
|
+
"spec/spec_helper.rb",
|
79
81
|
"spec/node/http_spec.rb",
|
80
|
-
"spec/node/routing_spec.rb",
|
81
|
-
"spec/node/zmq_xrepxreq_spec.rb",
|
82
|
-
"spec/node/zmq_pushpull_spec.rb",
|
83
82
|
"spec/node/nodelet_spec.rb",
|
83
|
+
"spec/node/routing_spec.rb",
|
84
84
|
"spec/node/websocket_spec.rb",
|
85
|
-
"spec/
|
86
|
-
"spec/
|
85
|
+
"spec/node/zmq_pushpull_spec.rb",
|
86
|
+
"spec/node/zmq_xrepxreq_spec.rb"
|
87
87
|
]
|
88
88
|
|
89
89
|
if s.respond_to? :specification_version then
|
@@ -96,7 +96,7 @@ Gem::Specification.new do |s|
|
|
96
96
|
s.add_runtime_dependency(%q<em-websocket>, [">= 0"])
|
97
97
|
s.add_runtime_dependency(%q<thin>, [">= 0"])
|
98
98
|
s.add_runtime_dependency(%q<zmqmachine>, [">= 0"])
|
99
|
-
s.add_runtime_dependency(%q<
|
99
|
+
s.add_runtime_dependency(%q<msgpack>, [">= 0"])
|
100
100
|
s.add_runtime_dependency(%q<json>, [">= 0"])
|
101
101
|
else
|
102
102
|
s.add_dependency(%q<ffi-rzmq>, [">= 0"])
|
@@ -104,7 +104,7 @@ Gem::Specification.new do |s|
|
|
104
104
|
s.add_dependency(%q<em-websocket>, [">= 0"])
|
105
105
|
s.add_dependency(%q<thin>, [">= 0"])
|
106
106
|
s.add_dependency(%q<zmqmachine>, [">= 0"])
|
107
|
-
s.add_dependency(%q<
|
107
|
+
s.add_dependency(%q<msgpack>, [">= 0"])
|
108
108
|
s.add_dependency(%q<json>, [">= 0"])
|
109
109
|
end
|
110
110
|
else
|
@@ -113,7 +113,7 @@ Gem::Specification.new do |s|
|
|
113
113
|
s.add_dependency(%q<em-websocket>, [">= 0"])
|
114
114
|
s.add_dependency(%q<thin>, [">= 0"])
|
115
115
|
s.add_dependency(%q<zmqmachine>, [">= 0"])
|
116
|
-
s.add_dependency(%q<
|
116
|
+
s.add_dependency(%q<msgpack>, [">= 0"])
|
117
117
|
s.add_dependency(%q<json>, [">= 0"])
|
118
118
|
end
|
119
119
|
end
|
data/example/subclass.rb
CHANGED
@@ -10,14 +10,14 @@ Thread.abort_on_exception = true
|
|
10
10
|
class TimestampedMessage < DripDrop::Message
|
11
11
|
def self.create_message(*args)
|
12
12
|
obj = super
|
13
|
-
obj.head[
|
14
|
-
obj.head[
|
13
|
+
obj.head['timestamps'] = []
|
14
|
+
obj.head['timestamps'] << Time.now.to_s
|
15
15
|
obj
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.recreate_message(*args)
|
19
19
|
obj = super
|
20
|
-
obj.head[
|
20
|
+
obj.head['timestamps'] << Time.now.to_s
|
21
21
|
obj
|
22
22
|
end
|
23
23
|
end
|
@@ -37,13 +37,13 @@ node = DripDrop::Node.new do
|
|
37
37
|
pull2 = zmq_pull("tcp://127.0.0.1:2202", :connect)
|
38
38
|
|
39
39
|
pull1.on_recv do |msg|
|
40
|
-
puts "Pull 1 #{msg.head}"
|
40
|
+
puts "Pull 1 #{msg.head.inspect}"
|
41
41
|
sleep 1
|
42
42
|
push2.send_message(msg)
|
43
43
|
end
|
44
44
|
|
45
45
|
pull2.on_recv do |msg|
|
46
|
-
puts "Pull 2 #{msg.head}"
|
46
|
+
puts "Pull 2 #{msg.head.inspect}"
|
47
47
|
end
|
48
48
|
|
49
49
|
push1.send_message(TimestampedMessage.create_message(:name => 'test', :body => "Hello there"))
|
data/lib/dripdrop/agent.rb
CHANGED
data/lib/dripdrop/message.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require '
|
2
|
+
require 'msgpack'
|
3
3
|
require 'json'
|
4
4
|
|
5
5
|
class DripDrop
|
@@ -11,8 +11,7 @@ class DripDrop
|
|
11
11
|
# body: anything you'd like, it can be null even
|
12
12
|
#
|
13
13
|
# Hashes, arrays, strings, integers, symbols, and floats are probably what you should stick to.
|
14
|
-
# Internally, they're just stored
|
15
|
-
# things like symbols and binary data are transmitted more efficiently and transparently.
|
14
|
+
# Internally, they're just stored using MsgPack, which is pretty much a super-fast, binary JSON
|
16
15
|
#
|
17
16
|
# The basic message format is built to mimic HTTP (s/url_path/name/). Why? Because I'm a dumb web developer :)
|
18
17
|
# The name is kind of like the URL, its what kind of message this is, but it's a loose definition,
|
@@ -24,22 +23,22 @@ class DripDrop
|
|
24
23
|
|
25
24
|
# Creates a new message.
|
26
25
|
# example:
|
27
|
-
# DripDrop::Message.new('mymessage',
|
26
|
+
# DripDrop::Message.new('mymessage', 'head' => {:timestamp => Time.now},
|
28
27
|
# :body => {:mykey => :myval, :other_key => ['complex']})
|
29
28
|
def initialize(name,extra={})
|
30
29
|
raise ArgumentError, "Message names may not be empty or null!" if name.nil? || name.empty?
|
31
30
|
|
32
|
-
@head = extra[:head] || {}
|
31
|
+
@head = extra[:head] || extra['head'] || {}
|
33
32
|
raise ArgumentError, "Invalid head #{@head}. Head must be a hash!" unless @head.is_a?(Hash)
|
34
|
-
@head[
|
33
|
+
@head['msg_class'] = self.class.to_s
|
35
34
|
|
36
35
|
@name = name
|
37
|
-
@body = extra[:body]
|
36
|
+
@body = extra[:body] || extra['body']
|
38
37
|
end
|
39
38
|
|
40
39
|
# The encoded message, ready to be sent across the wire via ZMQ
|
41
40
|
def encoded
|
42
|
-
|
41
|
+
self.to_hash.to_msgpack
|
43
42
|
end
|
44
43
|
|
45
44
|
# Encodes the hash represntation of the message to JSON
|
@@ -50,15 +49,17 @@ class DripDrop
|
|
50
49
|
def encode_json; json_encoded; end
|
51
50
|
|
52
51
|
# Convert the Message to a hash like:
|
53
|
-
# {
|
52
|
+
# {'name' => @name, 'head' => @head, 'body' => @body}
|
54
53
|
def to_hash
|
55
|
-
{
|
54
|
+
{'name' => @name, 'head' => @head, 'body' => @body}
|
56
55
|
end
|
57
56
|
|
58
57
|
# Build a new Message from a hash that looks like
|
59
|
-
# {:name => name, :body => body,
|
58
|
+
# {:name => name, :body => body, 'head' => head}
|
60
59
|
def self.from_hash(hash)
|
61
|
-
self.new(hash[:name]
|
60
|
+
self.new(hash[:name] || hash['name'],
|
61
|
+
:head => hash[:head] || hash['head'],
|
62
|
+
:body => hash[:body] || hash['body'])
|
62
63
|
end
|
63
64
|
|
64
65
|
def self.create_message(*args)
|
@@ -69,7 +70,8 @@ class DripDrop
|
|
69
70
|
end
|
70
71
|
|
71
72
|
def self.recreate_message(hash)
|
72
|
-
raise ArgumentError, "
|
73
|
+
raise ArgumentError, "Message missing head: #{hash.inspect}" unless hash['head']
|
74
|
+
raise ArgumentError, "Wrong message class #{hash['head']['msg_class']} for #{self.to_s}" unless hash['head']['msg_class'] == self.to_s
|
73
75
|
self.from_hash(hash)
|
74
76
|
end
|
75
77
|
|
@@ -82,7 +84,7 @@ class DripDrop
|
|
82
84
|
msg = msg.copy_out_string
|
83
85
|
return nil if msg.empty?
|
84
86
|
end
|
85
|
-
decoded =
|
87
|
+
decoded = MessagePack.unpack(msg)
|
86
88
|
self.recreate_message(decoded)
|
87
89
|
end
|
88
90
|
|
@@ -99,10 +101,10 @@ class DripDrop
|
|
99
101
|
end
|
100
102
|
|
101
103
|
# Keep this consistent
|
102
|
-
json_hash['head'][
|
104
|
+
json_hash['head']['msg_class'] = json_hash['head']['msg_class']
|
103
105
|
json_hash['head'].delete('msg_class')
|
104
106
|
|
105
|
-
self.new(json_hash['name'],
|
107
|
+
self.new(json_hash['name'], 'head' => json_hash['head'], :body => json_hash['body'])
|
106
108
|
end
|
107
109
|
end
|
108
110
|
|
@@ -121,12 +123,15 @@ class DripDrop
|
|
121
123
|
def verify_args(*args)
|
122
124
|
head =
|
123
125
|
case args[0]
|
124
|
-
when Hash
|
125
|
-
|
126
|
+
when Hash
|
127
|
+
az = args[0]
|
128
|
+
az[:head] || az['head']
|
129
|
+
else
|
130
|
+
args[1]
|
126
131
|
end
|
127
|
-
raise ArgumentError, "Invalid head #{head}. Head must be a hash!" unless head.is_a?(Hash)
|
132
|
+
raise ArgumentError, "Invalid head #{head.inspect}. Head must be a hash! (args: #{args.inspect})" unless head.is_a?(Hash)
|
128
133
|
|
129
|
-
msg_class = head[
|
134
|
+
msg_class = head['msg_class']
|
130
135
|
unless DripDrop::AutoMessageClass.message_subclasses.has_key?(msg_class)
|
131
136
|
raise ArgumentError, "Unknown AutoMessage message class #{msg_class}"
|
132
137
|
end
|
data/spec/message_spec.rb
CHANGED
@@ -9,8 +9,8 @@ describe DripDrop::Message do
|
|
9
9
|
def create_basic
|
10
10
|
attrs = {
|
11
11
|
:name => 'test',
|
12
|
-
:head => {
|
13
|
-
:body => [
|
12
|
+
:head => {'foo' => 'bar'},
|
13
|
+
:body => ['foo', 'bar', 'baz']
|
14
14
|
}
|
15
15
|
message = DripDrop::Message.new(attrs[:name],:head => attrs[:head],
|
16
16
|
:body => attrs[:body])
|
@@ -28,7 +28,7 @@ describe DripDrop::Message do
|
|
28
28
|
}.should_not raise_exception
|
29
29
|
end
|
30
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 == {
|
31
|
+
DripDrop::Message.new('nilhead', :head => nil).head.should == {'msg_class' => 'DripDrop::Message'}
|
32
32
|
end
|
33
33
|
it "should raise an exception if a non-hash, non-nil head is provided" do
|
34
34
|
lambda {
|
@@ -40,10 +40,10 @@ describe DripDrop::Message do
|
|
40
40
|
before(:all) do
|
41
41
|
@message, @attrs = create_basic
|
42
42
|
end
|
43
|
-
it "should encode to valid
|
43
|
+
it "should encode to valid MessagePack hash without error" do
|
44
44
|
enc = @message.encoded
|
45
45
|
enc.should be_a(String)
|
46
|
-
|
46
|
+
MessagePack.unpack(enc).should be_a(Hash)
|
47
47
|
end
|
48
48
|
it "should decode encoded messages without errors" do
|
49
49
|
DripDrop::Message.decode(@message.encoded).should be_a(DripDrop::Message)
|
@@ -67,8 +67,8 @@ describe DripDrop::Message do
|
|
67
67
|
def create_auto_message
|
68
68
|
attrs = {
|
69
69
|
:name => 'test',
|
70
|
-
:head => {
|
71
|
-
:body => [
|
70
|
+
:head => {'foo' => 'bar', 'msg_class' => 'SpecMessageClass'},
|
71
|
+
:body => ['foo', 'bar', 'baz']
|
72
72
|
}
|
73
73
|
|
74
74
|
message = DripDrop::AutoMessageClass.create_message(attrs)
|
@@ -81,21 +81,16 @@ describe DripDrop::Message do
|
|
81
81
|
it "should be added to the subclass message class hash if SubclassedMessage included" do
|
82
82
|
DripDrop::AutoMessageClass.message_subclasses.should include('SpecMessageClass' => SpecMessageClass)
|
83
83
|
end
|
84
|
-
it "should set the msg_class using a symbol, not a string when using JSON" do
|
85
|
-
msg = DripDrop::Message.decode_json(DripDrop::Message.new('test').json_encoded)
|
86
|
-
msg.head['msg_class'].should be_nil
|
87
|
-
msg.head[:msg_class].should == 'DripDrop::Message'
|
88
|
-
end
|
89
84
|
it "should throw an exception if we try to recreate a message of the wrong class" do
|
90
85
|
msg = DripDrop::Message.new('test')
|
91
86
|
lambda{SpecMessageClass.recreate_message(msg.to_hash)}.should raise_exception
|
92
87
|
end
|
93
88
|
|
94
89
|
describe "DripDrop::AutoMessageClass" do
|
95
|
-
it "should create a properly classed message based on head[
|
90
|
+
it "should create a properly classed message based on head['msg_class']" do
|
96
91
|
@message.should be_a(SpecMessageClass)
|
97
92
|
end
|
98
|
-
it "should recreate a message based on head[
|
93
|
+
it "should recreate a message based on head['msg_class']" do
|
99
94
|
DripDrop::AutoMessageClass.recreate_message(@message.to_hash).should be_a(SpecMessageClass)
|
100
95
|
end
|
101
96
|
end
|
data/spec/node/http_spec.rb
CHANGED
@@ -36,11 +36,11 @@ describe "http" do
|
|
36
36
|
@sent = []
|
37
37
|
10.times {|i| @sent << DripDrop::Message.new("test-#{i}")}
|
38
38
|
@client_responses = []
|
39
|
-
http_info = http_send_messages(@sent) do |sent_message,resp_message|
|
39
|
+
@http_info = http_send_messages(@sent) do |sent_message,resp_message|
|
40
40
|
@client_responses << {:sent_message => sent_message,
|
41
41
|
:resp_message => resp_message}
|
42
42
|
end
|
43
|
-
@responses = http_info[:responses]
|
43
|
+
@responses = @http_info[:responses]
|
44
44
|
end
|
45
45
|
|
46
46
|
it "should receive all sent messages" do
|
@@ -16,7 +16,7 @@ describe "zmq xreq/xrep" do
|
|
16
16
|
rep.on_recv do |message,response|
|
17
17
|
recvd << {:message => message, :response => response}
|
18
18
|
|
19
|
-
response.send_message :name => 'response', :body => {
|
19
|
+
response.send_message :name => 'response', :body => {'orig_name' => message.name}
|
20
20
|
end
|
21
21
|
|
22
22
|
to_send.each do |message|
|
@@ -47,7 +47,7 @@ describe "zmq xreq/xrep" do
|
|
47
47
|
|
48
48
|
it "should receive a reply message for each sent message" do
|
49
49
|
@sent.zip(@replied).each do |sent, replied|
|
50
|
-
replied.body[
|
50
|
+
replied.body['orig_name'].should == sent.name
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dripdrop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 6
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.6.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andrew Cholakian
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-12-17 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -89,7 +89,7 @@ dependencies:
|
|
89
89
|
type: :runtime
|
90
90
|
version_requirements: *id005
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
|
-
name:
|
92
|
+
name: msgpack
|
93
93
|
prerelease: false
|
94
94
|
requirement: &id006 !ruby/object:Gem::Requirement
|
95
95
|
none: false
|
@@ -211,13 +211,13 @@ signing_key:
|
|
211
211
|
specification_version: 3
|
212
212
|
summary: Evented framework for ZeroMQ and EventMachine Apps.
|
213
213
|
test_files:
|
214
|
-
- spec/spec_helper.rb
|
215
214
|
- spec/gimite-websocket.rb
|
215
|
+
- spec/message_spec.rb
|
216
|
+
- spec/node_spec.rb
|
217
|
+
- spec/spec_helper.rb
|
216
218
|
- spec/node/http_spec.rb
|
217
|
-
- spec/node/routing_spec.rb
|
218
|
-
- spec/node/zmq_xrepxreq_spec.rb
|
219
|
-
- spec/node/zmq_pushpull_spec.rb
|
220
219
|
- spec/node/nodelet_spec.rb
|
220
|
+
- spec/node/routing_spec.rb
|
221
221
|
- spec/node/websocket_spec.rb
|
222
|
-
- spec/
|
223
|
-
- spec/
|
222
|
+
- spec/node/zmq_pushpull_spec.rb
|
223
|
+
- spec/node/zmq_xrepxreq_spec.rb
|