dripdrop 0.9.6 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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