dripdrop 0.9.6 → 0.9.8

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/Rakefile CHANGED
@@ -13,9 +13,8 @@ begin
13
13
  gem.add_dependency('ffi-rzmq', '>= 0.7.1')
14
14
  gem.add_dependency('eventmachine', '>= 0.12.10')
15
15
  gem.add_dependency('em-websocket')
16
- gem.add_dependency('thin')
16
+ gem.add_dependency('eventmachine_httpserver')
17
17
  gem.add_dependency('em-zeromq', '>= 0.1.2')
18
- gem.add_dependency('msgpack')
19
18
  gem.add_dependency('yajl-ruby')
20
19
  end
21
20
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.6
1
+ 0.9.8
data/dripdrop.gemspec CHANGED
@@ -1,112 +1,106 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{dripdrop}
8
- s.version = "0.9.6"
8
+ s.version = "0.9.8"
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{2011-02-10}
12
+ s.date = %q{2011-02-15}
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 = [
16
16
  "LICENSE",
17
- "README.md"
17
+ "README.md"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "README.md",
24
- "Rakefile",
25
- "VERSION",
26
- "doc_img/topology.png",
27
- "dripdrop.gemspec",
28
- "example/agent_test.rb",
29
- "example/combined.rb",
30
- "example/complex/README",
31
- "example/complex/client.rb",
32
- "example/complex/server.rb",
33
- "example/complex/service.rb",
34
- "example/complex/websocket.rb",
35
- "example/http.rb",
36
- "example/pubsub.rb",
37
- "example/pushpull.rb",
38
- "example/subclass.rb",
39
- "example/xreq_xrep.rb",
40
- "js/dripdrop.html",
41
- "js/dripdrop.js",
42
- "js/qunit.css",
43
- "js/qunit.js",
44
- "lib/dripdrop.rb",
45
- "lib/dripdrop/agent.rb",
46
- "lib/dripdrop/handlers/base.rb",
47
- "lib/dripdrop/handlers/http.rb",
48
- "lib/dripdrop/handlers/websockets.rb",
49
- "lib/dripdrop/handlers/zeromq.rb",
50
- "lib/dripdrop/message.rb",
51
- "lib/dripdrop/node.rb",
52
- "lib/dripdrop/node/nodelet.rb",
53
- "spec/gimite-websocket.rb",
54
- "spec/message_spec.rb",
55
- "spec/node/http_spec.rb",
56
- "spec/node/nodelet_spec.rb",
57
- "spec/node/routing_spec.rb",
58
- "spec/node/websocket_spec.rb",
59
- "spec/node/zmq_pushpull_spec.rb",
60
- "spec/node/zmq_xrepxreq_spec.rb",
61
- "spec/node_spec.rb",
62
- "spec/spec_helper.rb"
21
+ "LICENSE",
22
+ "README.md",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "doc_img/topology.png",
26
+ "dripdrop.gemspec",
27
+ "example/agent_test.rb",
28
+ "example/combined.rb",
29
+ "example/complex/README",
30
+ "example/complex/client.rb",
31
+ "example/complex/server.rb",
32
+ "example/complex/service.rb",
33
+ "example/complex/websocket.rb",
34
+ "example/http.rb",
35
+ "example/pubsub.rb",
36
+ "example/pushpull.rb",
37
+ "example/subclass.rb",
38
+ "example/xreq_xrep.rb",
39
+ "js/dripdrop.html",
40
+ "js/dripdrop.js",
41
+ "js/qunit.css",
42
+ "js/qunit.js",
43
+ "lib/dripdrop.rb",
44
+ "lib/dripdrop/agent.rb",
45
+ "lib/dripdrop/handlers/base.rb",
46
+ "lib/dripdrop/handlers/http.rb",
47
+ "lib/dripdrop/handlers/websockets.rb",
48
+ "lib/dripdrop/handlers/zeromq.rb",
49
+ "lib/dripdrop/message.rb",
50
+ "lib/dripdrop/node.rb",
51
+ "lib/dripdrop/node/nodelet.rb",
52
+ "spec/gimite-websocket.rb",
53
+ "spec/message_spec.rb",
54
+ "spec/node/http_spec.rb",
55
+ "spec/node/nodelet_spec.rb",
56
+ "spec/node/routing_spec.rb",
57
+ "spec/node/websocket_spec.rb",
58
+ "spec/node/zmq_pushpull_spec.rb",
59
+ "spec/node/zmq_xrepxreq_spec.rb",
60
+ "spec/node_spec.rb",
61
+ "spec/spec_helper.rb"
63
62
  ]
64
63
  s.homepage = %q{http://github.com/andrewvc/dripdrop}
65
- s.rdoc_options = ["--charset=UTF-8"]
66
64
  s.require_paths = ["lib"]
67
- s.rubygems_version = %q{1.3.7}
65
+ s.rubygems_version = %q{1.5.1}
68
66
  s.summary = %q{Evented framework for ZeroMQ and EventMachine Apps.}
69
67
  s.test_files = [
68
+ "spec/gimite-websocket.rb",
69
+ "spec/message_spec.rb",
70
+ "spec/node/http_spec.rb",
71
+ "spec/node/nodelet_spec.rb",
72
+ "spec/node/routing_spec.rb",
73
+ "spec/node/websocket_spec.rb",
74
+ "spec/node/zmq_pushpull_spec.rb",
75
+ "spec/node/zmq_xrepxreq_spec.rb",
70
76
  "spec/node_spec.rb",
71
- "spec/spec_helper.rb",
72
- "spec/gimite-websocket.rb",
73
- "spec/message_spec.rb",
74
- "spec/node/nodelet_spec.rb",
75
- "spec/node/zmq_pushpull_spec.rb",
76
- "spec/node/zmq_xrepxreq_spec.rb",
77
- "spec/node/routing_spec.rb",
78
- "spec/node/websocket_spec.rb",
79
- "spec/node/http_spec.rb"
77
+ "spec/spec_helper.rb"
80
78
  ]
81
79
 
82
80
  if s.respond_to? :specification_version then
83
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
84
81
  s.specification_version = 3
85
82
 
86
83
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
87
84
  s.add_runtime_dependency(%q<ffi-rzmq>, [">= 0.7.1"])
88
85
  s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.10"])
89
86
  s.add_runtime_dependency(%q<em-websocket>, [">= 0"])
90
- s.add_runtime_dependency(%q<thin>, [">= 0"])
87
+ s.add_runtime_dependency(%q<eventmachine_httpserver>, [">= 0"])
91
88
  s.add_runtime_dependency(%q<em-zeromq>, [">= 0.1.2"])
92
- s.add_runtime_dependency(%q<msgpack>, [">= 0"])
93
89
  s.add_runtime_dependency(%q<yajl-ruby>, [">= 0"])
94
90
  else
95
91
  s.add_dependency(%q<ffi-rzmq>, [">= 0.7.1"])
96
92
  s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
97
93
  s.add_dependency(%q<em-websocket>, [">= 0"])
98
- s.add_dependency(%q<thin>, [">= 0"])
94
+ s.add_dependency(%q<eventmachine_httpserver>, [">= 0"])
99
95
  s.add_dependency(%q<em-zeromq>, [">= 0.1.2"])
100
- s.add_dependency(%q<msgpack>, [">= 0"])
101
96
  s.add_dependency(%q<yajl-ruby>, [">= 0"])
102
97
  end
103
98
  else
104
99
  s.add_dependency(%q<ffi-rzmq>, [">= 0.7.1"])
105
100
  s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
106
101
  s.add_dependency(%q<em-websocket>, [">= 0"])
107
- s.add_dependency(%q<thin>, [">= 0"])
102
+ s.add_dependency(%q<eventmachine_httpserver>, [">= 0"])
108
103
  s.add_dependency(%q<em-zeromq>, [">= 0.1.2"])
109
- s.add_dependency(%q<msgpack>, [">= 0"])
110
104
  s.add_dependency(%q<yajl-ruby>, [">= 0"])
111
105
  end
112
106
  end
data/example/http.rb CHANGED
@@ -14,7 +14,7 @@ DripDrop::Node.new do
14
14
  client = http_client(addr)
15
15
  msg = DripDrop::Message.new('http/status', :body => "Success #{i}")
16
16
  client.send_message(msg) do |resp_msg|
17
- puts resp_msg.inspect
17
+ puts "RESP: #{resp_msg.inspect}"
18
18
  end
19
19
  end
20
20
 
@@ -1,6 +1,27 @@
1
1
  class DripDrop
2
2
  class BaseHandler
3
3
 
4
+ def on_error(&block)
5
+ @err_cbak = block
6
+ end
7
+
8
+ def handle_error(exception,*extra)
9
+ if @err_cbak
10
+ begin
11
+ @err_cbak.call(exception,*extra)
12
+ rescue StandardError => e
13
+ print_exception(e)
14
+ end
15
+ else
16
+ print_exception(e)
17
+ end
18
+ end
19
+
20
+ def print_exception(exception)
21
+ $stderr.write exception.message
22
+ $stderr.write exception.backtrace.join("\t\n")
23
+ end
24
+
4
25
  private
5
26
  # Normalize Hash objs and DripDrop::Message objs into DripDrop::Message objs
6
27
  def dd_messagify(message)
@@ -1,89 +1,64 @@
1
- require 'thin'
2
- require 'thin_parser'
1
+ require 'eventmachine'
2
+ require 'evma_httpserver'
3
3
 
4
4
  class DripDrop
5
- class HTTPDeferrableBody < BaseHandler
6
- include EventMachine::Deferrable
7
-
8
- def call(body)
9
- body.each do |chunk|
10
- @body_callback.call(chunk)
11
- end
5
+ class HTTPServerHandlerResponse < BaseHandler
6
+ attr_reader :em_response, :message_class
7
+ def initialize(em_response)
8
+ @em_response = em_response
12
9
  end
13
10
 
14
- def each(&blk)
15
- @body_callback = blk
16
- end
17
-
18
- def send_message(raw_msg)
19
- msg = dd_messagify(raw_msg)
20
- if msg.is_a?(DripDrop::Message)
21
- json = msg.encode_json
22
- self.call([json])
23
- self.succeed
24
- else
25
- raise "Message Type '#{msg.class}' not supported"
26
- end
11
+ def send_message(message)
12
+ message = dd_messagify(message)
13
+ @em_response.status = 200
14
+ @em_response.content = message.json_encoded
15
+ @em_response.send_response
27
16
  end
28
17
  end
29
-
30
- class HTTPApp
18
+
19
+ class HTTPEMServer < EM::Connection
20
+ include EM::HttpServer
31
21
 
32
- AsyncResponse = [-1, {}, []].freeze
33
-
34
- def initialize(msg_format,&block)
35
- @msg_format = msg_format
36
- @recv_cbak = block
22
+ def initialize(dd_handler)
23
+ @dd_handler = dd_handler
24
+ end
25
+
26
+ def post_init
27
+ super
28
+ no_environment_strings
37
29
  end
38
30
 
39
- def call(env)
40
- body = HTTPDeferrableBody.new
41
-
42
- EM.next_tick do
43
- env['async.callback'].call([200, {'Content-Type' => 'text/plain', 'Access-Control-Allow-Origin' => '*'}, body])
44
- EM.next_tick do
45
- case @msg_format
46
- when :dripdrop_json
47
- msg = DripDrop::Message.decode_json(env['rack.input'].read)
48
- @recv_cbak.call(msg,body,env)
49
- else
50
- raise "Unsupported message type #{@msg_format}"
51
- end
52
- end
31
+ def process_http_request
32
+ begin
33
+ message = @dd_handler.message_class.decode_json(@http_post_content)
34
+ response = EM::DelegatedHttpResponse.new(self)
35
+ dd_response = HTTPServerHandlerResponse.new(response)
36
+ @dd_handler.recv_cbak.call(message, dd_response) if @dd_handler.recv_cbak
37
+ rescue StandardError => e
38
+ handler_error(e)
53
39
  end
54
-
55
- AsyncResponse
56
40
  end
57
41
  end
58
-
42
+
59
43
  class HTTPServerHandler < BaseHandler
60
- attr_reader :address, :opts
44
+ attr_reader :address, :opts, :message_class, :uri, :recv_cbak
61
45
 
62
46
  def initialize(uri,opts={})
63
- @uri = uri
64
- @address = uri.to_s
65
- @opts = opts
47
+ @uri = uri
48
+ @uri_path = @uri.path.empty? ? '/' : @uri.path
49
+ @address = uri.to_s
50
+ @opts = opts
66
51
  @message_class = @opts[:message_class] || DripDrop.default_message_class
67
52
  end
68
53
 
69
54
  def on_recv(msg_format=:dripdrop_json,&block)
70
- #Thin's error handling only rescues stuff w/o a backtrace
71
- begin
72
- Thin::Logging.silent = true
73
-
74
- uri_path = @uri.path.empty? ? '/' : @uri.path
75
-
76
- Thin::Server.start(@uri.host, @uri.port) do
77
- map uri_path do
78
- run HTTPApp.new(msg_format,&block)
79
- end
80
- end
81
- rescue Exception => e
82
- $stderr.write "Error in Thin server: #{e.message}\n#{e.backtrace.join("\n")}"
83
- end
55
+ @recv_cbak = block
56
+ @conn = EM.start_server(@uri.host, @uri.port, HTTPEMServer, self)
57
+ self
84
58
  end
85
59
  end
86
60
 
61
+
87
62
  class HTTPClientHandler < BaseHandler
88
63
  attr_reader :address, :opts
89
64
 
@@ -106,7 +81,14 @@ class DripDrop
106
81
  :content => dd_message.encode_json
107
82
  )
108
83
  req.callback do |response|
109
- block.call(@message_class.decode_json(response[:content]))
84
+ begin
85
+ # Hack to fix evma http
86
+ response[:content] =~ /(\{.*\})/
87
+ fixed_body = $1
88
+ block.call(@message_class.decode(fixed_body)) if block
89
+ rescue StandardError => e
90
+ handle_error(e)
91
+ end
110
92
  end
111
93
  else
112
94
  raise "Unsupported message type '#{dd_message.class}'"
@@ -1,37 +1,45 @@
1
1
  require 'em-websocket'
2
- require 'json'
2
+
3
3
 
4
4
  class DripDrop
5
5
  class WebSocketHandler < BaseHandler
6
+ class SocketError < StandardError; attr_accessor :reason, :connection end
7
+
6
8
  attr_reader :ws, :address, :thread
7
9
 
8
10
  def initialize(address,opts={})
9
- @raw = false #Deal in strings or ZMQ::Message objects
10
- host, port = address.host, address.port.to_i
11
- @debug = opts[:debug] || false
11
+ @opts = opts
12
+ @raw = false #Deal in strings or ZMQ::Message objects
13
+ host, port = address.host, address.port.to_i
14
+ @message_class = @opts[:message_class] || DripDrop.default_message_class
15
+ @debug = @opts[:debug] || false
12
16
 
13
17
  EventMachine::WebSocket.start(:host => host,:port => port,:debug => @debug) do |ws|
14
18
  #A WebSocketHandler:Connection gets passed to all callbacks
15
19
  dd_conn = Connection.new(ws)
16
20
 
17
- ws.onopen { @onopen_handler.call(dd_conn) if @onopen_handler }
21
+ ws.onopen { @onopen_handler.call(dd_conn) if @onopen_handler }
18
22
  ws.onclose { @onclose_handler.call(dd_conn) if @onclose_handler }
19
- ws.onerror {|reason| @onerror_handler.call(reason, dd_conn) if @onerror_handler }
23
+ ws.onerror {|reason|
24
+ e = SocketError.new
25
+ e.reason = reason
26
+ e.connection = dd_conn
27
+ handle_error(e)
28
+ }
20
29
 
21
- ws.onmessage do |message|
30
+ ws.onmessage { |message|
22
31
  if @onmessage_handler
23
32
  begin
24
- message = DripDrop::Message.decode_json(message) unless @raw
33
+ message = @message_class.decode(message) unless @raw
34
+ @onmessage_handler.call(message,dd_conn)
25
35
  rescue StandardError => e
26
- $stderr.write "Could not parse message: #{e.message}" if @debug
36
+ handle_error(e,dd_conn)
27
37
  end
28
-
29
- @onmessage_handler.call(message,dd_conn)
30
38
  end
31
- end
39
+ }
32
40
  end
33
41
  end
34
-
42
+
35
43
  def on_recv(&block)
36
44
  @raw = false
37
45
  @onmessage_handler = block
@@ -53,11 +61,6 @@ class DripDrop
53
61
  @onclose_handler = block
54
62
  self
55
63
  end
56
-
57
- def on_error(&block)
58
- @onerror_handler = block
59
- self
60
- end
61
64
  end
62
65
 
63
66
  class WebSocketHandler::Connection < BaseHandler
@@ -69,7 +72,8 @@ class DripDrop
69
72
  end
70
73
 
71
74
  def send_message(message)
72
- @ws.send(dd_messagify(message).to_hash.to_json)
75
+ encoded_message = dd_messagify(message).encoded
76
+ @ws.send(encoded_message)
73
77
  end
74
78
  end
75
79
  end
@@ -38,7 +38,7 @@ class DripDrop
38
38
  def initialize(*args)
39
39
  super(*args)
40
40
  @send_queue = []
41
- @send_queue_enabled = true
41
+ @send_queue_enabled = false
42
42
  end
43
43
 
44
44
  def on_writable(socket)
@@ -48,7 +48,7 @@ class DripDrop
48
48
  num_parts = message.length
49
49
  message.each_with_index do |part,i|
50
50
  # Set the multi-part flag unless this is the last message
51
- flags = (i + 1 < num_parts ? ZMQ::SNDMORE : 0) + ZMQ::NOBLOCK
51
+ flags = (i + 1 < num_parts ? ZMQ::SNDMORE : 0) | ZMQ::NOBLOCK
52
52
 
53
53
  if part.class == ZMQ::Message
54
54
  socket.send(part, flags)
@@ -104,15 +104,19 @@ class DripDrop
104
104
  end
105
105
 
106
106
  def on_readable(socket, messages)
107
- case @msg_format
108
- when :raw
109
- @recv_cbak.call(messages)
110
- when :dripdrop
111
- raise "Expected message in one part" if messages.length > 1
112
- body = messages.shift.copy_out_string
113
- @recv_cbak.call(decode_message(body))
114
- else
115
- raise "Unknown message format '#{@msg_format}'"
107
+ begin
108
+ case @msg_format
109
+ when :raw
110
+ @recv_cbak.call(messages)
111
+ when :dripdrop
112
+ raise "Expected message in one part" if messages.length > 1
113
+ body = messages.shift.copy_out_string
114
+ @recv_cbak.call(decode_message(body))
115
+ else
116
+ raise "Unknown message format '#{@msg_format}'"
117
+ end
118
+ rescue StandardError => e
119
+ handle_error(e)
116
120
  end
117
121
  end
118
122
 
@@ -255,8 +259,12 @@ class DripDrop
255
259
  end
256
260
 
257
261
  def on_readable(socket, messages)
258
- # Strip out empty delimiter
259
- super(socket, messages[1..-1])
262
+ begin
263
+ # Strip out empty delimiter
264
+ super(socket, messages[1..-1])
265
+ rescue StandardError => e
266
+ handle_error(e)
267
+ end
260
268
  end
261
269
  end
262
270
  end
@@ -1,9 +1,15 @@
1
1
  require 'rubygems'
2
- require 'msgpack'
3
- require 'yajl'
2
+
3
+ if PLATFORM == 'java'
4
+ require 'json'
5
+ else
6
+ require 'yajl'
7
+ require 'yajl/json_gem'
8
+ end
4
9
 
5
10
  class DripDrop
6
11
  class WrongMessageClassError < StandardError; end
12
+
7
13
  # DripDrop::Message messages are exchanged between all tiers in the architecture
8
14
  # A Message is composed of a name, head, and body, and should be restricted to types that
9
15
  # can be readily encoded to JSON.
@@ -40,12 +46,12 @@ class DripDrop
40
46
 
41
47
  # The encoded message, ready to be sent across the wire via ZMQ
42
48
  def encoded
43
- self.to_hash.to_msgpack
49
+ self.to_hash.to_json
44
50
  end
45
51
 
46
- # Encodes the hash represntation of the message to JSON
52
+ # (Deprecated) Encodes the hash represntation of the message to JSON
47
53
  def json_encoded
48
- Yajl::Encoder.encode self.to_hash
54
+ encoded
49
55
  end
50
56
  # (Deprecated, use json_encoded)
51
57
  def encode_json; json_encoded; end
@@ -73,40 +79,56 @@ class DripDrop
73
79
 
74
80
  def self.recreate_message(hash)
75
81
  raise ArgumentError, "Message missing head: #{hash.inspect}" unless hash['head']
76
- raise DripDrop::WrongMessageClassError, "Wrong message class #{hash['head']['message_class']} for #{self.to_s}" unless hash['head']['message_class'] == self.to_s
77
- self.from_hash(hash)
82
+
83
+ klass = (hash['head'] && hash['head']['message_class']) ? constantize(hash['head']['message_class']) : nil
84
+ if klass && (!(klass == self) && !self.subclasses.include?(klass))
85
+ raise DripDrop::WrongMessageClassError, "Wrong message class '#{klass}', expected '#{self}'"
86
+ end
87
+
88
+ klass ? klass.from_hash(hash) : self.from_hash(hash)
78
89
  end
79
90
 
80
91
  # Parses an already encoded string
81
92
  def self.decode(msg)
82
93
  return nil if msg.nil? || msg.empty?
83
- #This makes parsing ZMQ messages less painful, even if its ugly here
84
- #We check the class name as a string in case we don't have ZMQ loaded
85
- if msg.class.to_s == 'ZMQ::Message'
86
- msg = msg.copy_out_string
87
- return nil if msg.empty?
88
- end
89
- decoded = MessagePack.unpack(msg)
94
+
95
+ decoded = JSON.parse(msg)
90
96
  self.recreate_message(decoded)
91
97
  end
92
98
 
93
99
  # (Deprecated). Use decode instead
94
100
  def self.parse(msg); self.decode(msg) end
95
101
 
96
- # Decodes a string containing a JSON representation of a message
102
+ # (Deprecated) Decodes a string containing a JSON representation of a message
97
103
  def self.decode_json(str)
104
+ self.decode(str)
105
+ end
106
+
107
+ def self.constantize(str)
98
108
  begin
99
- json_hash = Yajl::Parser.parse(str)
100
- rescue Yajl::ParseError => e
101
- puts "Could not parse msg '#{str}': #{e.message}"
102
- return nil
109
+ str.split('::').inject(Object) {|memo,name|
110
+ memo = memo.const_get(name); memo
111
+ }
112
+ rescue NameError => e
113
+ nil
103
114
  end
104
-
105
- # Keep this consistent
106
- json_hash['head']['message_class'] = json_hash['head']['message_class']
107
- json_hash['head'].delete('message_class')
108
-
109
- self.new(json_hash['name'], 'head' => json_hash['head'], :body => json_hash['body'])
115
+ end
116
+
117
+ #Used for reconstructing messages
118
+ def self.subclasses(direct = false)
119
+ classes = []
120
+ if direct
121
+ ObjectSpace.each_object(Class) do |c|
122
+ next unless c.superclass == self
123
+ classes << c
124
+ end
125
+ else
126
+ ObjectSpace.each_object(Class) do |c|
127
+ next unless c.ancestors.include?(self) and (c != self)
128
+ classes << c
129
+ end
130
+ end
131
+ classes
110
132
  end
111
133
  end
112
134
 
@@ -157,6 +179,7 @@ class DripDrop
157
179
  end
158
180
  end
159
181
 
182
+
160
183
  #Including this module into your subclass will automatically register the class
161
184
  #with AutoMessageClass
162
185
  module SubclassedMessage
@@ -3,10 +3,15 @@ class DripDrop::Node
3
3
  class Nodelet
4
4
  attr_accessor :name, :routing
5
5
 
6
- def initialize(ctx, name, routes)
6
+ def initialize(ctx, name, *configure_args)
7
7
  @ctx = ctx
8
8
  @name = name
9
9
  @internal_routing = {}
10
+ configure(*configure_args)
11
+ end
12
+
13
+ def configure(*args)
14
+ # Do nothing!
10
15
  end
11
16
 
12
17
  def route(name,handler_type,*handler_args)
data/lib/dripdrop/node.rb CHANGED
@@ -138,8 +138,8 @@ class DripDrop
138
138
  #
139
139
  # If you specify a block, Nodelet#action will be ignored and the block
140
140
  # will be run
141
- def nodelet(name,klass=Nodelet,&block)
142
- nlet = @nodelets[name] ||= klass.new(self,name,routing)
141
+ def nodelet(name,klass=Nodelet,*configure_args,&block)
142
+ nlet = @nodelets[name] ||= klass.new(self,name,*configure_args)
143
143
  if block
144
144
  block.call(nlet)
145
145
  else
@@ -147,7 +147,7 @@ class DripDrop
147
147
  end
148
148
  nlet
149
149
  end
150
-
150
+
151
151
  # Creates a ZMQ::SUB type socket. Can only receive messages via +on_recv+.
152
152
  # zmq_subscribe sockets have a +topic_filter+ option, which restricts which
153
153
  # messages they can receive. It takes a regexp as an option.
@@ -269,7 +269,8 @@ class DripDrop
269
269
  end
270
270
 
271
271
  # Catch all error handler
272
- def error_handler(e)
272
+ # Global to all DripDrop Nodes
273
+ def self.error_handler(e)
273
274
  $stderr.write "#{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
274
275
  end
275
276
 
data/spec/message_spec.rb CHANGED
@@ -40,19 +40,14 @@ describe DripDrop::Message do
40
40
  before(:all) do
41
41
  @message, @attrs = create_basic
42
42
  end
43
- it "should encode to valid MessagePack hash without error" do
43
+ it "should encode to valid JSON hash without error" do
44
44
  enc = @message.encoded
45
45
  enc.should be_a(String)
46
- MessagePack.unpack(enc).should be_a(Hash)
46
+ JSON.parse(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)
50
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
51
  it "should decode JSON encoded messages without errors" do
57
52
  DripDrop::Message.decode_json(@message.json_encoded).should be_a(DripDrop::Message)
58
53
  end
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'set'
4
+
3
5
  describe "http" do
4
6
 
5
7
  def http_send_messages(to_send,addr=rand_addr('http'),&block)
@@ -4,6 +4,7 @@ describe "websockets" do
4
4
  def websockets_send_messages(to_send,&block)
5
5
  received = []
6
6
  responses = []
7
+ seen_signatures = Set.new
7
8
  server = nil
8
9
 
9
10
  open_message = DripDrop::Message.new('open', :body => 'test')
@@ -13,12 +14,13 @@ describe "websockets" do
13
14
 
14
15
  error_occured = false
15
16
 
16
- @node = run_reactor(1) do
17
+ @node = run_reactor(2) do
17
18
  addr = rand_addr('ws')
18
19
 
19
20
  server = websocket(addr)
20
21
  server.on_open do |conn|
21
22
  conn.send_message(open_message)
23
+ seen_signatures << conn.signature
22
24
  end.on_recv do |message,conn|
23
25
  received << message
24
26
  conn.send_message(message)
@@ -30,7 +32,7 @@ describe "websockets" do
30
32
 
31
33
  EM.defer do
32
34
  client = WebSocket.new(addr)
33
- open_received = DripDrop::Message.decode_json(client.receive)
35
+ open_received = DripDrop::Message.decode(client.receive)
34
36
  to_send.each do |message|
35
37
  client.send(message.json_encoded)
36
38
  end
@@ -41,6 +43,10 @@ describe "websockets" do
41
43
  recvd_count += 1
42
44
  end
43
45
  client.close
46
+
47
+ # This one only connects to test unique signatures
48
+ client2 = WebSocket.new(addr)
49
+ client2.close
44
50
  end
45
51
 
46
52
  zmq_subscribe(rand_addr, :bind) {} #Keep zmqmachine happy
@@ -48,8 +54,8 @@ describe "websockets" do
48
54
 
49
55
  {:received => received, :responses => responses,
50
56
  :open_message => open_message, :open_received => open_received,
51
- :close_occured => close_occured, :error_occured => error_occured,
52
- :handlers => {:server => server }}
57
+ :close_occured => close_occured, :error_occured => error_occured,
58
+ :seen_signatures => seen_signatures,:handlers => {:server => server }}
53
59
  end
54
60
  describe "basic sending and receiving" do
55
61
  before(:all) do
@@ -84,5 +90,9 @@ describe "websockets" do
84
90
  it "should not generate an error event" do
85
91
  @ws_info[:error_occured].should be_false
86
92
  end
93
+
94
+ it "should see unique connection signatures for each client" do
95
+ @ws_info[:seen_signatures].length.should == 2
96
+ end
87
97
  end
88
98
  end
data/spec/node_spec.rb CHANGED
@@ -72,6 +72,7 @@ describe DripDrop::Node do
72
72
  class TestException < StandardError; end
73
73
 
74
74
  it "should rescue exceptions in the EM reactor" do
75
+ pending "Not sure if this feature is a good idea"
75
76
  expectations = an_instance_of(TestException)
76
77
  reactor = run_reactor do
77
78
  self.should_receive(:error_handler).with(expectations)
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), %w[. .. lib dripdrop]))
2
+ require 'set'
3
+
2
4
  Thread.abort_on_exception = true
3
5
 
4
6
  # Used to test websocket clients.
metadata CHANGED
@@ -1,127 +1,84 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dripdrop
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 9
9
- - 6
10
- version: 0.9.6
4
+ prerelease:
5
+ version: 0.9.8
11
6
  platform: ruby
12
7
  authors:
13
- - Andrew Cholakian
8
+ - Andrew Cholakian
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-02-10 00:00:00 -08:00
13
+ date: 2011-02-15 00:00:00 -08:00
19
14
  default_executable:
20
15
  dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: ffi-rzmq
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 1
30
- segments:
31
- - 0
32
- - 7
33
- - 1
34
- version: 0.7.1
35
- type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: eventmachine
39
- prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 59
46
- segments:
47
- - 0
48
- - 12
49
- - 10
50
- version: 0.12.10
51
- type: :runtime
52
- version_requirements: *id002
53
- - !ruby/object:Gem::Dependency
54
- name: em-websocket
55
- prerelease: false
56
- requirement: &id003 !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- hash: 3
62
- segments:
63
- - 0
64
- version: "0"
65
- type: :runtime
66
- version_requirements: *id003
67
- - !ruby/object:Gem::Dependency
68
- name: thin
69
- prerelease: false
70
- requirement: &id004 !ruby/object:Gem::Requirement
71
- none: false
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- hash: 3
76
- segments:
77
- - 0
78
- version: "0"
79
- type: :runtime
80
- version_requirements: *id004
81
- - !ruby/object:Gem::Dependency
82
- name: em-zeromq
83
- prerelease: false
84
- requirement: &id005 !ruby/object:Gem::Requirement
85
- none: false
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- hash: 31
90
- segments:
91
- - 0
92
- - 1
93
- - 2
94
- version: 0.1.2
95
- type: :runtime
96
- version_requirements: *id005
97
- - !ruby/object:Gem::Dependency
98
- name: msgpack
99
- prerelease: false
100
- requirement: &id006 !ruby/object:Gem::Requirement
101
- none: false
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- hash: 3
106
- segments:
107
- - 0
108
- version: "0"
109
- type: :runtime
110
- version_requirements: *id006
111
- - !ruby/object:Gem::Dependency
112
- name: yajl-ruby
113
- prerelease: false
114
- requirement: &id007 !ruby/object:Gem::Requirement
115
- none: false
116
- requirements:
117
- - - ">="
118
- - !ruby/object:Gem::Version
119
- hash: 3
120
- segments:
121
- - 0
122
- version: "0"
123
- type: :runtime
124
- version_requirements: *id007
16
+ - !ruby/object:Gem::Dependency
17
+ name: ffi-rzmq
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.7.1
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: eventmachine
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 0.12.10
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: em-websocket
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: eventmachine_httpserver
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ type: :runtime
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: em-zeromq
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.2
69
+ type: :runtime
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: yajl-ruby
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ type: :runtime
81
+ version_requirements: *id006
125
82
  description: "Evented framework for ZeroMQ and EventMachine Apps. "
126
83
  email: andrew@andrewvc.com
127
84
  executables: []
@@ -129,94 +86,87 @@ executables: []
129
86
  extensions: []
130
87
 
131
88
  extra_rdoc_files:
132
- - LICENSE
133
- - README.md
89
+ - LICENSE
90
+ - README.md
134
91
  files:
135
- - .document
136
- - .gitignore
137
- - LICENSE
138
- - README.md
139
- - Rakefile
140
- - VERSION
141
- - doc_img/topology.png
142
- - dripdrop.gemspec
143
- - example/agent_test.rb
144
- - example/combined.rb
145
- - example/complex/README
146
- - example/complex/client.rb
147
- - example/complex/server.rb
148
- - example/complex/service.rb
149
- - example/complex/websocket.rb
150
- - example/http.rb
151
- - example/pubsub.rb
152
- - example/pushpull.rb
153
- - example/subclass.rb
154
- - example/xreq_xrep.rb
155
- - js/dripdrop.html
156
- - js/dripdrop.js
157
- - js/qunit.css
158
- - js/qunit.js
159
- - lib/dripdrop.rb
160
- - lib/dripdrop/agent.rb
161
- - lib/dripdrop/handlers/base.rb
162
- - lib/dripdrop/handlers/http.rb
163
- - lib/dripdrop/handlers/websockets.rb
164
- - lib/dripdrop/handlers/zeromq.rb
165
- - lib/dripdrop/message.rb
166
- - lib/dripdrop/node.rb
167
- - lib/dripdrop/node/nodelet.rb
168
- - spec/gimite-websocket.rb
169
- - spec/message_spec.rb
170
- - spec/node/http_spec.rb
171
- - spec/node/nodelet_spec.rb
172
- - spec/node/routing_spec.rb
173
- - spec/node/websocket_spec.rb
174
- - spec/node/zmq_pushpull_spec.rb
175
- - spec/node/zmq_xrepxreq_spec.rb
176
- - spec/node_spec.rb
177
- - spec/spec_helper.rb
92
+ - .document
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - VERSION
97
+ - doc_img/topology.png
98
+ - dripdrop.gemspec
99
+ - example/agent_test.rb
100
+ - example/combined.rb
101
+ - example/complex/README
102
+ - example/complex/client.rb
103
+ - example/complex/server.rb
104
+ - example/complex/service.rb
105
+ - example/complex/websocket.rb
106
+ - example/http.rb
107
+ - example/pubsub.rb
108
+ - example/pushpull.rb
109
+ - example/subclass.rb
110
+ - example/xreq_xrep.rb
111
+ - js/dripdrop.html
112
+ - js/dripdrop.js
113
+ - js/qunit.css
114
+ - js/qunit.js
115
+ - lib/dripdrop.rb
116
+ - lib/dripdrop/agent.rb
117
+ - lib/dripdrop/handlers/base.rb
118
+ - lib/dripdrop/handlers/http.rb
119
+ - lib/dripdrop/handlers/websockets.rb
120
+ - lib/dripdrop/handlers/zeromq.rb
121
+ - lib/dripdrop/message.rb
122
+ - lib/dripdrop/node.rb
123
+ - lib/dripdrop/node/nodelet.rb
124
+ - spec/gimite-websocket.rb
125
+ - spec/message_spec.rb
126
+ - spec/node/http_spec.rb
127
+ - spec/node/nodelet_spec.rb
128
+ - spec/node/routing_spec.rb
129
+ - spec/node/websocket_spec.rb
130
+ - spec/node/zmq_pushpull_spec.rb
131
+ - spec/node/zmq_xrepxreq_spec.rb
132
+ - spec/node_spec.rb
133
+ - spec/spec_helper.rb
178
134
  has_rdoc: true
179
135
  homepage: http://github.com/andrewvc/dripdrop
180
136
  licenses: []
181
137
 
182
138
  post_install_message:
183
- rdoc_options:
184
- - --charset=UTF-8
139
+ rdoc_options: []
140
+
185
141
  require_paths:
186
- - lib
142
+ - lib
187
143
  required_ruby_version: !ruby/object:Gem::Requirement
188
144
  none: false
189
145
  requirements:
190
- - - ">="
191
- - !ruby/object:Gem::Version
192
- hash: 3
193
- segments:
194
- - 0
195
- version: "0"
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: "0"
196
149
  required_rubygems_version: !ruby/object:Gem::Requirement
197
150
  none: false
198
151
  requirements:
199
- - - ">="
200
- - !ruby/object:Gem::Version
201
- hash: 3
202
- segments:
203
- - 0
204
- version: "0"
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: "0"
205
155
  requirements: []
206
156
 
207
157
  rubyforge_project:
208
- rubygems_version: 1.3.7
158
+ rubygems_version: 1.5.1
209
159
  signing_key:
210
160
  specification_version: 3
211
161
  summary: Evented framework for ZeroMQ and EventMachine Apps.
212
162
  test_files:
213
- - spec/node_spec.rb
214
- - spec/spec_helper.rb
215
- - spec/gimite-websocket.rb
216
- - spec/message_spec.rb
217
- - spec/node/nodelet_spec.rb
218
- - spec/node/zmq_pushpull_spec.rb
219
- - spec/node/zmq_xrepxreq_spec.rb
220
- - spec/node/routing_spec.rb
221
- - spec/node/websocket_spec.rb
222
- - spec/node/http_spec.rb
163
+ - spec/gimite-websocket.rb
164
+ - spec/message_spec.rb
165
+ - spec/node/http_spec.rb
166
+ - spec/node/nodelet_spec.rb
167
+ - spec/node/routing_spec.rb
168
+ - spec/node/websocket_spec.rb
169
+ - spec/node/zmq_pushpull_spec.rb
170
+ - spec/node/zmq_xrepxreq_spec.rb
171
+ - spec/node_spec.rb
172
+ - spec/spec_helper.rb
data/.gitignore DELETED
@@ -1,26 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
- *.swo
16
-
17
- ## PROJECT::GENERAL
18
- coverage
19
- rdoc
20
- doc
21
- pkg
22
-
23
- #RBX
24
- *.rbc
25
-
26
- ## PROJECT::SPECIFIC