dripdrop 0.10.0-java

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.
Files changed (47) hide show
  1. data/.document +5 -0
  2. data/.gitignore +31 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE +20 -0
  5. data/README.md +164 -0
  6. data/Rakefile +16 -0
  7. data/dripdrop.gemspec +37 -0
  8. data/example/agent_test.rb +14 -0
  9. data/example/combined.rb +33 -0
  10. data/example/complex/README +22 -0
  11. data/example/complex/client.rb +20 -0
  12. data/example/complex/server.rb +102 -0
  13. data/example/complex/service.rb +8 -0
  14. data/example/complex/websocket.rb +442 -0
  15. data/example/http.rb +23 -0
  16. data/example/pubsub.rb +29 -0
  17. data/example/pushpull.rb +21 -0
  18. data/example/subclass.rb +54 -0
  19. data/example/xreq_xrep.rb +24 -0
  20. data/js/dripdrop.html +186 -0
  21. data/js/dripdrop.js +107 -0
  22. data/js/qunit.css +155 -0
  23. data/js/qunit.js +1261 -0
  24. data/lib/dripdrop.rb +2 -0
  25. data/lib/dripdrop/agent.rb +40 -0
  26. data/lib/dripdrop/handlers/base.rb +42 -0
  27. data/lib/dripdrop/handlers/http_client.rb +38 -0
  28. data/lib/dripdrop/handlers/http_server.rb +59 -0
  29. data/lib/dripdrop/handlers/mongrel2.rb +163 -0
  30. data/lib/dripdrop/handlers/websocket_server.rb +86 -0
  31. data/lib/dripdrop/handlers/zeromq.rb +300 -0
  32. data/lib/dripdrop/message.rb +190 -0
  33. data/lib/dripdrop/node.rb +351 -0
  34. data/lib/dripdrop/node/nodelet.rb +35 -0
  35. data/lib/dripdrop/version.rb +3 -0
  36. data/spec/gimite-websocket.rb +442 -0
  37. data/spec/message_spec.rb +94 -0
  38. data/spec/node/http_spec.rb +77 -0
  39. data/spec/node/nodelet_spec.rb +67 -0
  40. data/spec/node/routing_spec.rb +67 -0
  41. data/spec/node/websocket_spec.rb +98 -0
  42. data/spec/node/zmq_m2_spec.rb +77 -0
  43. data/spec/node/zmq_pushpull_spec.rb +54 -0
  44. data/spec/node/zmq_xrepxreq_spec.rb +108 -0
  45. data/spec/node_spec.rb +85 -0
  46. data/spec/spec_helper.rb +20 -0
  47. metadata +167 -0
data/example/http.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'dripdrop/node'
2
+ Thread.abort_on_exception = true
3
+
4
+ DripDrop::Node.new do
5
+ addr = 'http://127.0.0.1:2200'
6
+
7
+ i = 0
8
+ http_server(addr).on_recv do |msg,response|
9
+ i += 1
10
+ response.send_message(msg)
11
+ end
12
+
13
+ EM::PeriodicTimer.new(1) do
14
+ client = http_client(addr)
15
+ msg = DripDrop::Message.new('http/status', :body => "Success #{i}")
16
+ client.send_message(msg) do |resp_msg|
17
+ puts "RESP: #{resp_msg.inspect}"
18
+ end
19
+ end
20
+
21
+ #Keep zmqmachine from spinning around using up all our CPU by creating a socket
22
+ req = zmq_xreq('tcp://127.0.0.1:2091', :connect)
23
+ end.start!
data/example/pubsub.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'dripdrop/node'
3
+ Thread.abort_on_exception = true
4
+
5
+ #Define our handlers
6
+ DripDrop::Node.new do
7
+ route :pub, :zmq_publish, 'tcp://localhost:2200', :bind
8
+ route :sub1, :zmq_subscribe, pub.address, :connect, :topic_filter => /[13579]$/
9
+ route :sub2, :zmq_subscribe, pub.address, :connect, :topic_filter => /[02468]$/
10
+ route :sub3, :zmq_subscribe, pub.address, :connect
11
+
12
+ sub1.on_recv do |message|
13
+ puts "Receiver 1 #{message.inspect}"
14
+ end
15
+
16
+ sub2.on_recv do |message|
17
+ puts "Receiver 2 #{message.inspect}"
18
+ end
19
+
20
+ sub3.on_recv do |message|
21
+ puts "Receiver 3 #{message.inspect}"
22
+ end
23
+
24
+ zm_reactor.periodical_timer(500) do
25
+ puts "Sending!"
26
+ #Sending a hash as a message implicitly transforms it into a DripDrop::Message
27
+ pub.send_message(:name => Time.now.to_i.to_s, :body => 'Test Payload')
28
+ end
29
+ end.start! #Start the reactor and block until complete
@@ -0,0 +1,21 @@
1
+ require 'dripdrop/node'
2
+ Thread.abort_on_exception = true
3
+
4
+ DripDrop::Node.new do
5
+ z_addr = 'tcp://127.0.0.1:2200'
6
+
7
+ zmq_pull(z_addr, :connect).on_recv do |message|
8
+ puts "Receiver 2 #{message.body}"
9
+ end
10
+ zmq_pull(z_addr, :connect).on_recv do |message|
11
+ puts "Receiver 1 #{message.body}"
12
+ end
13
+ push = zmq_push(z_addr, :bind)
14
+
15
+ i = 0
16
+ EM::PeriodicTimer.new(1) do
17
+ i += 1
18
+ puts i
19
+ push.send_message(:name => 'test', :body => "Test Payload #{i}")
20
+ end
21
+ end.start!
@@ -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.to_s
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.inspect}"
41
+ sleep 1
42
+ push2.send_message(msg)
43
+ end
44
+
45
+ pull2.on_recv do |msg|
46
+ puts "Pull 2 #{msg.head.inspect}"
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
@@ -0,0 +1,24 @@
1
+ require 'dripdrop/node'
2
+ Thread.abort_on_exception = true
3
+
4
+ DripDrop::Node.new do
5
+ route :xrep_server, :zmq_xrep, 'tcp://127.0.0.1:2200', :bind
6
+ route :xreq_client, :zmq_xreq, xrep_server.address, :connect
7
+
8
+ xrep_server.on_recv do |message,response|
9
+ puts "REP #{message.body}"
10
+ response.send_message(message)
11
+ end
12
+
13
+ i = 0; k = 0
14
+ EM::PeriodicTimer.new(1) do
15
+ i += 1; k += 1
16
+
17
+ xreq_client.send_message(:name => 'test', :body => "Test Payload i#{i}") do |message|
18
+ puts "RECV I RESP #{message.inspect}"
19
+ end
20
+ xreq_client.send_message(:name => 'test', :body => "Test Payload k#{i}") do |message|
21
+ puts "RECV K RESP #{message.inspect}"
22
+ end
23
+ end
24
+ end.start!
data/js/dripdrop.html ADDED
@@ -0,0 +1,186 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2
+ "http://www.w3.org/TR/html4/loose.dtd">
3
+ <html>
4
+ <head>
5
+ <script src="../jquery.js"></script>
6
+ <script src="../jquery.json.js"></script>
7
+ <script src="../dripdrop.js"></script>
8
+
9
+ <link rel="stylesheet" href="qunit.css" type="text/css" media="screen" />
10
+ <script type="text/javascript" src="qunit.js"></script>
11
+ <script type="text/javascript" src="jack.js"></script>
12
+
13
+ <script>
14
+ $(document).ready(function(){
15
+
16
+ /* Test Helpers */
17
+ function TSock() {return new DD.WebSocket('ws://localhost:2702')};
18
+ function THTTP() {return new DD.HTTP('http://localhost:2703')};
19
+
20
+ //Faked message to for a websocket
21
+ function FakeWSMessage(ddMessage) {
22
+ var msg = (ddMessage === undefined) ? new DD.Message('test') : ddMessage;
23
+ this.data = msg.jsonEncoded();
24
+ }
25
+
26
+ /* Tests */
27
+
28
+ test("The DD Singleton should be constructed from DripDrop", function() {
29
+ equals( DripDrop, DD.constructor, "Match");
30
+ });
31
+
32
+ module("DD.Message");
33
+
34
+ var msgVals = {
35
+ name: 'foo',
36
+ body: 'bar',
37
+ head: {key: 'baz'}
38
+ }
39
+ test("Creation: Name Only", function() {
40
+ var msg = new DD.Message(msgVals.name);
41
+ equals(msg.name, msgVals.name, "name");
42
+ });
43
+ test("Creation: Name + Body", function() {
44
+ var msg = new DD.Message(msgVals.name, {body : msgVals.body});
45
+ equals(msg.name, msgVals.name, "name");
46
+ equals(msg.body, msgVals.body, "body");
47
+ });
48
+ test("Creation: Name + Head + Body", function() {
49
+ var msg = new DD.Message(msgVals.name,
50
+ {body : msgVals.body, head : msgVals.head});
51
+ expect(3);
52
+ equals(msg.name, msgVals.name, "name");
53
+ equals(msg.head, msgVals.head, "head");
54
+ equals(msg.body, msgVals.body, "body");
55
+ });
56
+ test("Creation: No Head should still have head as an object", function() {
57
+ var msg = new DD.Message(msgVals.name);
58
+ equals(msg.head.constructor, Object, "head");
59
+ });
60
+
61
+ test("JSON Export", function() {
62
+ var msg = new DD.Message(msgVals.name,
63
+ {body : msgVals.body, head : msgVals.head});
64
+ equals(msg.jsonEncoded().constructor, String, "jsonEncoded");
65
+ });
66
+
67
+ module("DD.WebSocket");
68
+
69
+ test("Creating a websocket should make available the raw socket", function() {
70
+ var tSock = new TSock;
71
+ equals(tSock.socket.constructor, WebSocket,'raw socket');
72
+ });
73
+
74
+ $([['onOpen','onopen'],
75
+ ['onClose','onclose'],
76
+ ['onError','onerror']]).each(function(i,pair) {
77
+ var dd_func = pair[0];
78
+ var ws_func = pair[1];
79
+
80
+ test("DD function " + dd_func + " should set WS func " + ws_func, function() {
81
+ var tSock = new TSock;
82
+ var tFunc = function() {};
83
+ tSock[dd_func](tFunc);
84
+ equals(tSock.socket[ws_func], tFunc, "Func Set");
85
+ });
86
+ });
87
+
88
+ test("onRecv should trigger the passed in callback", function() {
89
+ expect(3);
90
+
91
+ var expectedMsg = new DD.Message('foo');
92
+
93
+ var tSock = new TSock;
94
+ tSock.onRecv(function(msg) {
95
+ ok(true, "Function executed");
96
+ equals(msg.constructor,DD.Message, "Is a DD.Message");
97
+ equals(msg.name, expectedMsg.name);
98
+ });
99
+
100
+ tSock.socket.onmessage(new FakeWSMessage(expectedMsg));
101
+ });
102
+
103
+ test("sendMessage should send a string to the websocket", function() {
104
+ expect(1);
105
+
106
+ var tSock = new TSock;
107
+ var tMsg = new DD.Message('foo');
108
+ tSock.socket.send = function(message) {
109
+ equals(tMsg.jsonEncoded(), message);
110
+ }
111
+ console.log(tSock.sendMessage)
112
+ tSock.sendMessage(tMsg);
113
+ });
114
+
115
+ module("DD.HTTP");
116
+
117
+ test("Creation", function() {
118
+ var dht = new DD.HTTP;
119
+ equals(dht.constructor, DD.HTTP, "Constructor Match");
120
+ });
121
+
122
+ test("Sending a message should call a get posting a JSON representation of the data",function() {
123
+ expect(1);
124
+ var tHTTP = new THTTP;
125
+ tHTTP.sendMessage();
126
+ });
127
+
128
+
129
+ module("DD.Pipeline");
130
+
131
+ test("Creation", function() {
132
+ var pl = new DD.Pipeline;
133
+ equals(pl.constructor, DD.Pipeline, "Constructor Match");
134
+ });
135
+
136
+ test("Should expose the pipeline stages as an array", function() {
137
+ var pl = new DD.Pipeline;
138
+ equals(pl.stages.constructor, Array, "Constructor Match");
139
+ });
140
+
141
+ test("Should return null when no stages", function() {
142
+ equals((new DD.Pipeline).execute(new DD.Message('test')), null);
143
+ });
144
+
145
+ test("Should return null when no stages", function() {
146
+ equals((new DD.Pipeline).execute(new DD.Message('test')), null);
147
+ });
148
+
149
+ //This tests too many things at once, should be broken apart
150
+ test("Execution, Order, Message Transformation", function() {
151
+ expect(5);
152
+
153
+ var pl = new DD.Pipeline;
154
+
155
+ var s1 = new DD.PipelineStage('t1','Test1',function(message) {
156
+ ok(true,"Test1 Executed");
157
+ equals(message.name,0,"Executed first job first");
158
+ message.name = 1;
159
+ return message;
160
+ });
161
+ var s2 = new DD.PipelineStage('t2','Test2',function(message) {
162
+ ok(true,"Test2 Executed");
163
+ equals(message.name,1,"Executed second job after first");
164
+ message.name = 2;
165
+
166
+ return message;
167
+ });
168
+ pl.stages = [s1,s2];
169
+
170
+ var resMsg = pl.execute(new DD.Message('0'));
171
+ equals(resMsg.name,2);
172
+ });
173
+
174
+ }); //End of tests
175
+
176
+ </script>
177
+
178
+ </head>
179
+ <body>
180
+ <h1 id="qunit-header">DripDrop Tests</h1>
181
+ <h2 id="qunit-banner"></h2>
182
+ <h2 id="qunit-userAgent"></h2>
183
+ <ol id="qunit-tests"></ol>
184
+ <div id="qunit-fixture">test markup, will be hidden</div>
185
+ </body>
186
+ </html>
data/js/dripdrop.js ADDED
@@ -0,0 +1,107 @@
1
+ function DripDrop() {
2
+ /* JavaScript object for DripDrop Messages */
3
+ this.Message = function(name,opts) {
4
+ this.name = name;
5
+ if (opts && opts.body) {
6
+ this.body = opts.body;
7
+ };
8
+
9
+ this.head = (opts && opts.head !== undefined) ? opts.head : {empty:''};
10
+
11
+ this.jsonEncoded = function() {
12
+ return JSON.stringify({name: this.name, head: this.head, body: this.body});
13
+ };
14
+ };
15
+
16
+ /* A DripDrop friendly WebSocket Object.
17
+ This automatically converts messages to DD.Message objects.
18
+ Additionally, this uses friendlier callback methods, closer to the DripDrop
19
+ server-side API, like onOpen, onRecv, onError, and onClose. */
20
+ this.WebSocket = function(url) {
21
+ this.socket = new WebSocket(url);
22
+
23
+ this.onOpen = function(callback) {
24
+ this.socket.onopen = callback;
25
+ return this;
26
+ };
27
+
28
+ this.onRecv = function(callback) {
29
+ this.socket.onmessage = function(wsMessage) {
30
+ var json = $.parseJSON(wsMessage.data)
31
+ var message = new DD.Message(json.name, {head: json.head, body: json.body});
32
+
33
+ callback(message);
34
+ }
35
+ return this;
36
+ };
37
+
38
+ this.onClose = function(callback) {
39
+ this.socket.onclose = callback;
40
+ return this;
41
+ };
42
+
43
+ this.onError = function(callback) {
44
+ this.socket.onerror = callback;
45
+ return this;
46
+ };
47
+
48
+ this.sendMessage = function(message) {
49
+ this.socket.send(message.jsonEncoded());
50
+ return this;
51
+ };
52
+ };
53
+
54
+ this.HTTPResponse = function() {
55
+
56
+ };
57
+
58
+ /* A DripDrop friendly HTTP Request. */
59
+ this.HTTP = function(url) {
60
+ this.url = url;
61
+
62
+ this.onRecv = function(data) {};
63
+ this.sendMessage = function() {
64
+ var response = new this.HTTPResponse;
65
+ $.post(this.url, function(json) {
66
+ this.onRecv(new DD.Message(json.name, {head: json.head, body: json.body}));
67
+ });
68
+ };
69
+ };
70
+
71
+ /* An Object for reperesenting pipeline processing.
72
+ Ex:
73
+ var mypl = new DD.Pipeline;
74
+ mypl.stages.push(new DD.PipelineStage{'namecapper','Name Capper',
75
+ function(message) { message.name = message.name.toUpperCase() });
76
+ mypl.execute(message); //Message must be a valid DD.Message
77
+
78
+
79
+ All functions must either return a message, or false.
80
+ If false is returned the pipeline short-circuits and returns false, not running
81
+ subsequent stages */
82
+ this.PipelineStage = function(id,name,action) {
83
+ this.id = id;
84
+ this.name = name;
85
+ this.action = action;
86
+ };
87
+
88
+ this.Pipeline = function() {
89
+ this.stages = [];
90
+
91
+ this.execute = function(message) {
92
+ if (this.stages.length == 0) {
93
+ return null;
94
+ };
95
+
96
+ for (var i=0,l=this.stages.length; i < l; i++) {
97
+ var stage = this.stages[i];
98
+ message = stage.action(message);
99
+ };
100
+
101
+ return message;
102
+ };
103
+ };
104
+ };
105
+
106
+ //Use this as shorthand
107
+ DD = new DripDrop;