dripdrop 0.3.1 → 0.4.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 +23 -28
- data/VERSION +1 -1
- data/dripdrop.gemspec +25 -3
- data/example/combined.rb +33 -0
- data/example/pubsub.rb +7 -15
- data/example/stats_app/core.rb +113 -0
- data/example/stats_app/public/.sass-cache/b48b4299d80c05f528daf63fe51d85e5e3c10d98/stats.scssc +0 -0
- data/example/stats_app/public/backbone.js +16 -0
- data/example/stats_app/public/build_templates.rb +5 -0
- data/example/stats_app/public/json2.js +482 -0
- data/example/stats_app/public/protovis-r3.2.js +277 -0
- data/example/stats_app/public/stats.css +5 -0
- data/example/stats_app/public/stats.haml +61 -0
- data/example/stats_app/public/stats.html +26 -0
- data/example/stats_app/public/stats.js +113 -0
- data/example/stats_app/public/stats.scss +10 -0
- data/example/stats_app/public/underscore.js +17 -0
- data/example/xreq_xrep.rb +9 -11
- data/js/dripdrop.js +6 -2
- data/lib/dripdrop/handlers/base.rb +18 -0
- data/lib/dripdrop/handlers/http.rb +18 -18
- data/lib/dripdrop/handlers/websockets.rb +33 -26
- data/lib/dripdrop/handlers/zeromq.rb +30 -24
- data/lib/dripdrop/message.rb +5 -0
- data/lib/dripdrop/node/nodelet.rb +29 -0
- data/lib/dripdrop/node.rb +103 -25
- data/spec/gimite-websocket.rb +442 -0
- data/spec/message_spec.rb +5 -0
- data/spec/node/http_spec.rb +2 -8
- data/spec/node/nodelet_spec.rb +57 -0
- data/spec/node/routing_spec.rb +68 -0
- data/spec/node/websocket_spec.rb +88 -0
- data/spec/node/zmq_pushpull_spec.rb +2 -6
- data/spec/node/zmq_xrepxreq_spec.rb +24 -24
- data/spec/node_spec.rb +0 -1
- data/spec/spec_helper.rb +17 -3
- metadata +27 -5
- data/js/jack.js +0 -876
@@ -0,0 +1,26 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>DripDrop Stats</title>
|
4
|
+
<link href='stats.css' rel='stylesheet' />
|
5
|
+
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js' type='text/javascript'></script>
|
6
|
+
<script src='json2.js' type='text/javascript'></script>
|
7
|
+
<script src='../../../js/dripdrop.js' type='text/javascript'></script>
|
8
|
+
<script src='underscore.js' type='text/javascript'></script>
|
9
|
+
<script src='backbone.js' type='text/javascript'></script>
|
10
|
+
<script src='protovis-r3.2.js' type='text/javascript'></script>
|
11
|
+
<script src='stats.js' type='text/javascript'></script>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<h1>DripDrop Stats</h1>
|
15
|
+
<form id="traceroute">
|
16
|
+
Traceroute IP:<input type="text" id="traceroute-ip">
|
17
|
+
<a href="#" onclick='submitTraceForm(); return false;'>Submit</a>
|
18
|
+
</form>
|
19
|
+
<div id="force-cont"></div>
|
20
|
+
<script type='text/javascript'>
|
21
|
+
$(function () {
|
22
|
+
window.renderForce();
|
23
|
+
});
|
24
|
+
</script>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,113 @@
|
|
1
|
+
$(function() {
|
2
|
+
window.submitTraceForm = function () {
|
3
|
+
var ip = $('#traceroute-ip').val();
|
4
|
+
var msg = new DD.Message('ip_trace_req', {body: {ip: ip}});
|
5
|
+
$.post('http://stringer.andrewvc.com:8082', msg.jsonEncoded(), function (msg) {
|
6
|
+
console.log(msg);
|
7
|
+
});
|
8
|
+
return false;
|
9
|
+
};
|
10
|
+
|
11
|
+
var forceData = {};
|
12
|
+
|
13
|
+
var ws = new DD.WebSocket('ws://stringer.andrewvc.com:2202');
|
14
|
+
ws.onOpen(function () {
|
15
|
+
}).onRecv(function (message) {
|
16
|
+
if (message.name != 'ip_route') return;
|
17
|
+
|
18
|
+
forceData[message.body.ip] = message.body.route;
|
19
|
+
}).onClose(function () {
|
20
|
+
|
21
|
+
}).onError(function () {
|
22
|
+
|
23
|
+
});
|
24
|
+
|
25
|
+
setInterval(function() {
|
26
|
+
window.renderForce();
|
27
|
+
}, 3000);
|
28
|
+
|
29
|
+
|
30
|
+
var processForceData = function () {
|
31
|
+
var oldforceData = {
|
32
|
+
'127.0.0.1': ['192.168.2.1', '192.291.12.2', 'router.what.com'],
|
33
|
+
'127.0.2.1': ['192.168.3.1', '192.291.12.2', 'router.what.com'],
|
34
|
+
'127.5.0.1': ['192.168.2.1', '192.291.12.2', 'router.what.com'],
|
35
|
+
'127.2.5.1': ['192.16.6.1', '192.291.12.2', 'router.what.com'],
|
36
|
+
'127.2.1.1': ['192.16.2.6', '192.211.12.2', 'router.what.com'],
|
37
|
+
'127.0.0.2': ['192.168.2.1', '192.291.12.2', 'router.what.com'],
|
38
|
+
}
|
39
|
+
|
40
|
+
var addrs = _.reduce(
|
41
|
+
forceData,
|
42
|
+
function (memo,addrs) {
|
43
|
+
_.each(addrs, function(addr) {
|
44
|
+
if (! memo[addr]) {
|
45
|
+
memo[addr] = 1;
|
46
|
+
}
|
47
|
+
});
|
48
|
+
return memo;
|
49
|
+
},
|
50
|
+
{}
|
51
|
+
);
|
52
|
+
|
53
|
+
var i = 0;
|
54
|
+
var nodes = [];
|
55
|
+
var addrs_idx_map = {};
|
56
|
+
for (var addr in addrs) {
|
57
|
+
nodes.push({nodeName: addr, group: 1});
|
58
|
+
addrs_idx_map[addr] = i;
|
59
|
+
i++;
|
60
|
+
};
|
61
|
+
|
62
|
+
var links = [];
|
63
|
+
_.each(
|
64
|
+
forceData,
|
65
|
+
function (addrs) {
|
66
|
+
if (addrs.length >= 2) {
|
67
|
+
//We can skip the last element
|
68
|
+
for (var i=0; i < addrs.length - 1; i++) {
|
69
|
+
var source = addrs_idx_map[addrs[i]];
|
70
|
+
var target = addrs_idx_map[addrs[i+1]];
|
71
|
+
links.push({source: source, target: target, value: 2});
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
);
|
76
|
+
|
77
|
+
return({nodes: nodes, links: links});
|
78
|
+
}
|
79
|
+
window.renderForce = function () {
|
80
|
+
var data = processForceData();
|
81
|
+
|
82
|
+
var w = document.body.clientWidth,
|
83
|
+
h = document.body.clientHeight,
|
84
|
+
colors = pv.Colors.category19();
|
85
|
+
|
86
|
+
var vis = new pv.Panel()
|
87
|
+
.canvas($('#force-cont')[0])
|
88
|
+
.width(w)
|
89
|
+
.height(h)
|
90
|
+
.fillStyle("white")
|
91
|
+
.event("mousedown", pv.Behavior.pan())
|
92
|
+
.event("mousewheel", pv.Behavior.zoom());
|
93
|
+
|
94
|
+
var force = vis.add(pv.Layout.Force)
|
95
|
+
.nodes(data.nodes)
|
96
|
+
.links(data.links);
|
97
|
+
//.nodes([{nodeName: '127.0.0.1', group: 1}, {nodeName: '192.168.1.1', group: 2}])
|
98
|
+
//.links([{source: 1, target: 0, value: 1}]);
|
99
|
+
|
100
|
+
force.link.add(pv.Line);
|
101
|
+
|
102
|
+
force.node.add(pv.Dot)
|
103
|
+
.size(function(d) {return (d.linkDegree + 4) * Math.pow(this.scale, -1.5)})
|
104
|
+
.fillStyle(function(d) { return d.fix ? "brown" : colors(d.group) })
|
105
|
+
.strokeStyle(function() { return this.fillStyle().darker() } )
|
106
|
+
.lineWidth(1)
|
107
|
+
.title(function(d) { return d.nodeName } )
|
108
|
+
.event("mousedown", function () { return pv.Behavior.drag() })
|
109
|
+
.event("drag", function () { return force });
|
110
|
+
|
111
|
+
vis.render();
|
112
|
+
}
|
113
|
+
});
|
@@ -0,0 +1,17 @@
|
|
1
|
+
(function(){var o=this,A=o._,r=typeof StopIteration!=="undefined"?StopIteration:"__break__",k=Array.prototype,m=Object.prototype,i=k.slice,B=k.unshift,C=m.toString,p=m.hasOwnProperty,s=k.forEach,t=k.map,u=k.reduce,v=k.reduceRight,w=k.filter,x=k.every,y=k.some,n=k.indexOf,z=k.lastIndexOf;m=Array.isArray;var D=Object.keys,b=function(a){return new l(a)};if(typeof exports!=="undefined")exports._=b;o._=b;b.VERSION="1.1.2";var j=b.each=b.forEach=function(a,c,d){try{if(s&&a.forEach===s)a.forEach(c,d);else if(b.isNumber(a.length))for(var e=
|
2
|
+
0,f=a.length;e<f;e++)c.call(d,a[e],e,a);else for(e in a)p.call(a,e)&&c.call(d,a[e],e,a)}catch(g){if(g!=r)throw g;}return a};b.map=function(a,c,d){if(t&&a.map===t)return a.map(c,d);var e=[];j(a,function(f,g,h){e[e.length]=c.call(d,f,g,h)});return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){if(u&&a.reduce===u){if(e)c=b.bind(c,e);return a.reduce(c,d)}j(a,function(f,g,h){d=c.call(e,d,f,g,h)});return d};b.reduceRight=b.foldr=function(a,c,d,e){if(v&&a.reduceRight===v){if(e)c=b.bind(c,e);return a.reduceRight(c,
|
3
|
+
d)}a=(b.isArray(a)?a.slice():b.toArray(a)).reverse();return b.reduce(a,c,d,e)};b.find=b.detect=function(a,c,d){var e;j(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.filter=b.select=function(a,c,d){if(w&&a.filter===w)return a.filter(c,d);var e=[];j(a,function(f,g,h){if(c.call(d,f,g,h))e[e.length]=f});return e};b.reject=function(a,c,d){var e=[];j(a,function(f,g,h){c.call(d,f,g,h)||(e[e.length]=f)});return e};b.every=b.all=function(a,c,d){c=c||b.identity;if(x&&a.every===x)return a.every(c,
|
4
|
+
d);var e=true;j(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.some=b.any=function(a,c,d){c=c||b.identity;if(y&&a.some===y)return a.some(c,d);var e=false;j(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=b.contains=function(a,c){if(n&&a.indexOf===n)return a.indexOf(c)!=-1;var d=false;j(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck=
|
5
|
+
function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};j(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};j(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(e,
|
6
|
+
f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){var g=e.criteria,h=f.criteria;return g<h?-1:g>h?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return i.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,c,d){return c&&!d?i.call(a,
|
7
|
+
0,c):a[0]};b.rest=b.tail=function(a,c,d){return i.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.filter(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c[c.length]=d;return c},[])};b.without=function(a){var c=i.call(arguments,1);return b.filter(a,function(d){return!b.include(c,d)})};b.uniq=b.unique=function(a,c){return b.reduce(a,function(d,e,f){if(0==f||(c===true?
|
8
|
+
b.last(d)!=e:!b.include(d,e)))d[d.length]=e;return d},[])};b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(d){return b.every(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c){if(n&&a.indexOf===n)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(z&&a.lastIndexOf===
|
9
|
+
z)return a.lastIndexOf(c);for(var d=a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=i.call(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.max(Math.ceil((c-a)/d),0);f=0;for(var g=Array(e);f<e;){g[f++]=a;a+=d}return g};b.bind=function(a,c){var d=i.call(arguments,2);return function(){return a.apply(c||{},d.concat(i.call(arguments)))}};b.bindAll=function(a){var c=i.call(arguments,1);if(c.length==0)c=b.functions(a);j(c,function(d){a[d]=b.bind(a[d],a)});return a};
|
10
|
+
b.memoize=function(a,c){var d={};c=c||b.identity;return function(){var e=c.apply(this,arguments);return e in d?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,c){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.wrap=function(a,c){return function(){var d=[a].concat(i.call(arguments));return c.apply(c,d)}};b.compose=function(){var a=i.call(arguments);return function(){for(var c=i.call(arguments),
|
11
|
+
d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=D||function(a){if(b.isArray(a))return b.range(0,a.length);var c=[],d;for(d in a)if(p.call(a,d))c[c.length]=d;return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){return b.filter(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a){j(i.call(arguments,1),function(c){for(var d in c)a[d]=c[d]});return a};b.clone=function(a){return b.isArray(a)?a.slice():b.extend({},a)};b.tap=
|
12
|
+
function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false;if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return false;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;
|
13
|
+
d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!(f in c)||!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(p.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=m||function(a){return!!(a&&a.concat&&a.unshift&&!a.callee)};b.isArguments=function(a){return!!(a&&a.callee)};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};
|
14
|
+
b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return a===+a||C.call(a)==="[object Number]"};b.isBoolean=function(a){return a===true||a===false};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=
|
15
|
+
function(){o._=A;return this};b.identity=function(a){return a};b.times=function(a,c,d){for(var e=0;e<a;e++)c.call(d,e)};b.breakLoop=function(){throw r;};b.mixin=function(a){j(b.functions(a),function(c){E(c,b[c]=a[c])})};var F=0;b.uniqueId=function(a){var c=F++;return a?a+c:c};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/'/g,
|
16
|
+
"\\'").replace(d.interpolate,function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return c?d(c):d};var l=function(a){this._wrapped=a};b.prototype=l.prototype;var q=function(a,c){return c?b(a).chain():a},E=function(a,c){l.prototype[a]=function(){var d=i.call(arguments);B.call(d,
|
17
|
+
this._wrapped);return q(c.apply(b,d),this._chain)}};b.mixin(b);j(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=k[a];l.prototype[a]=function(){c.apply(this._wrapped,arguments);return q(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var c=k[a];l.prototype[a]=function(){return q(c.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})();
|
data/example/xreq_xrep.rb
CHANGED
@@ -2,24 +2,22 @@ require 'dripdrop/node'
|
|
2
2
|
Thread.abort_on_exception = true
|
3
3
|
|
4
4
|
DripDrop::Node.new do
|
5
|
-
|
5
|
+
route :xrep_server, :zmq_xrep, 'tcp://127.0.0.1:2200', :bind
|
6
|
+
route :xreq_client, :zmq_xreq, xrep_server.address, :connect
|
6
7
|
|
7
|
-
|
8
|
-
rep.on_recv do |message,identities,seq|
|
8
|
+
xrep_server.on_recv do |message,response|
|
9
9
|
puts "REP #{message.body}"
|
10
|
-
|
10
|
+
response.send_message(message)
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
i = 0
|
16
|
-
k = 0
|
17
|
-
|
13
|
+
i = 0; k = 0
|
18
14
|
zm_reactor.periodical_timer(1000) do
|
19
|
-
|
15
|
+
i += 1; k += 1
|
16
|
+
|
17
|
+
xreq_client.send_message(:name => 'test', :body => "Test Payload i#{i}") do |message|
|
20
18
|
puts "RECV I RESP #{message.inspect}"
|
21
19
|
end
|
22
|
-
|
20
|
+
xreq_client.send_message(:name => 'test', :body => "Test Payload k#{i}") do |message|
|
23
21
|
puts "RECV K RESP #{message.inspect}"
|
24
22
|
end
|
25
23
|
end
|
data/js/dripdrop.js
CHANGED
@@ -9,7 +9,7 @@ function DripDrop() {
|
|
9
9
|
this.head = (opts && opts.head !== undefined) ? opts.head : {empty:''};
|
10
10
|
|
11
11
|
this.jsonEncoded = function() {
|
12
|
-
return
|
12
|
+
return JSON.stringify({name: this.name, head: this.head, body: this.body});
|
13
13
|
};
|
14
14
|
};
|
15
15
|
|
@@ -22,6 +22,7 @@ function DripDrop() {
|
|
22
22
|
|
23
23
|
this.onOpen = function(callback) {
|
24
24
|
this.socket.onopen = callback;
|
25
|
+
return this;
|
25
26
|
};
|
26
27
|
|
27
28
|
this.onRecv = function(callback) {
|
@@ -30,20 +31,23 @@ function DripDrop() {
|
|
30
31
|
var message = new DD.Message(json.name, {head: json.head, body: json.body});
|
31
32
|
|
32
33
|
callback(message);
|
33
|
-
return this;
|
34
34
|
}
|
35
|
+
return this;
|
35
36
|
};
|
36
37
|
|
37
38
|
this.onClose = function(callback) {
|
38
39
|
this.socket.onclose = callback;
|
40
|
+
return this;
|
39
41
|
};
|
40
42
|
|
41
43
|
this.onError = function(callback) {
|
42
44
|
this.socket.onerror = callback;
|
45
|
+
return this;
|
43
46
|
};
|
44
47
|
|
45
48
|
this.sendMessage = function(message) {
|
46
49
|
this.socket.send(message.jsonEncoded());
|
50
|
+
return this;
|
47
51
|
};
|
48
52
|
};
|
49
53
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class DripDrop
|
2
|
+
class BaseHandler
|
3
|
+
|
4
|
+
private
|
5
|
+
# Normalize Hash objs and DripDrop::Message objs into DripDrop::Message objs
|
6
|
+
def dd_messagify(message)
|
7
|
+
if message.is_a?(Hash)
|
8
|
+
return DripDrop::Message.new(message[:name], :head => message[:head],
|
9
|
+
:body => message[:body])
|
10
|
+
elsif message.is_a?(DripDrop::Message)
|
11
|
+
return message
|
12
|
+
else
|
13
|
+
return message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -2,7 +2,7 @@ require 'thin'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
class DripDrop
|
5
|
-
class HTTPDeferrableBody
|
5
|
+
class HTTPDeferrableBody < BaseHandler
|
6
6
|
include EventMachine::Deferrable
|
7
7
|
|
8
8
|
def call(body)
|
@@ -15,13 +15,14 @@ class DripDrop
|
|
15
15
|
@body_callback = blk
|
16
16
|
end
|
17
17
|
|
18
|
-
def send_message(
|
18
|
+
def send_message(raw_msg)
|
19
|
+
msg = dd_messagify(raw_msg)
|
19
20
|
if msg.class == DripDrop::Message
|
20
21
|
json = msg.encode_json
|
21
22
|
self.call([json])
|
22
23
|
self.succeed
|
23
24
|
else
|
24
|
-
raise "Message Type not supported"
|
25
|
+
raise "Message Type '#{msg.class}' not supported"
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
@@ -33,7 +34,6 @@ class DripDrop
|
|
33
34
|
def initialize(msg_format,&block)
|
34
35
|
@msg_format = msg_format
|
35
36
|
@recv_cbak = block
|
36
|
-
super
|
37
37
|
end
|
38
38
|
|
39
39
|
def call(env)
|
@@ -45,8 +45,7 @@ class DripDrop
|
|
45
45
|
case @msg_format
|
46
46
|
when :dripdrop_json
|
47
47
|
msg = DripDrop::Message.decode_json(env['rack.input'].read)
|
48
|
-
msg
|
49
|
-
@recv_cbak.call(msg,body)
|
48
|
+
@recv_cbak.call(msg,body,env)
|
50
49
|
else
|
51
50
|
raise "Unsupported message type #{@msg_format}"
|
52
51
|
end
|
@@ -57,43 +56,44 @@ class DripDrop
|
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
|
-
class HTTPServerHandler
|
59
|
+
class HTTPServerHandler < BaseHandler
|
61
60
|
attr_reader :address, :opts
|
62
61
|
|
63
|
-
def initialize(
|
64
|
-
@
|
62
|
+
def initialize(uri,opts={})
|
63
|
+
@uri = uri
|
64
|
+
@address = uri.to_s
|
65
65
|
@opts = opts
|
66
66
|
end
|
67
67
|
|
68
68
|
def on_recv(msg_format=:dripdrop_json,&block)
|
69
|
-
#Rack middleware was not meant to be used this way...
|
70
69
|
#Thin's error handling only rescues stuff w/o a backtrace
|
71
70
|
begin
|
72
|
-
Thin::Logging.
|
73
|
-
|
74
|
-
Thin::Server.start(@
|
71
|
+
Thin::Logging.silent = true
|
72
|
+
|
73
|
+
Thin::Server.start(@uri.host, @uri.port) do
|
75
74
|
map '/' do
|
76
75
|
run HTTPApp.new(msg_format,&block)
|
77
76
|
end
|
78
77
|
end
|
79
78
|
rescue Exception => e
|
80
|
-
puts e.message
|
79
|
+
puts "Error in Thin server: #{e.message}\n#{e.backtrace.join("\n")}"
|
81
80
|
end
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
85
|
-
class HTTPClientHandler
|
84
|
+
class HTTPClientHandler < BaseHandler
|
86
85
|
attr_reader :address, :opts
|
87
86
|
|
88
|
-
def initialize(
|
89
|
-
@
|
87
|
+
def initialize(uri, opts={})
|
88
|
+
@uri = uri
|
89
|
+
@address = @uri.to_s
|
90
90
|
@opts = opts
|
91
91
|
end
|
92
92
|
|
93
93
|
def send_message(msg,&block)
|
94
94
|
if msg.class == DripDrop::Message
|
95
95
|
req = EM::Protocols::HttpClient.request(
|
96
|
-
:host =>
|
96
|
+
:host => @uri.host, :port => @uri.port,
|
97
97
|
:request => '/', :verb => 'POST',
|
98
98
|
:contenttype => 'application/json',
|
99
99
|
:content => msg.encode_json
|
@@ -2,39 +2,33 @@ require 'em-websocket'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
class DripDrop
|
5
|
-
class WebSocketHandler
|
5
|
+
class WebSocketHandler < BaseHandler
|
6
6
|
attr_reader :ws, :address, :thread
|
7
7
|
|
8
8
|
def initialize(address,opts={})
|
9
9
|
@raw = false #Deal in strings or ZMQ::Message objects
|
10
|
-
|
11
|
-
|
12
|
-
@debug = opts[:debug] || false
|
10
|
+
host, port = address.host, address.port.to_i
|
11
|
+
@debug = opts[:debug] || false
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
@onmessage_handler.call(message,ws) if @onmessage_handler
|
30
|
-
end
|
31
|
-
@ws.onclose do
|
32
|
-
@onclose_handler.call(@ws) if @onclose_handler
|
33
|
-
end
|
34
|
-
@ws.onerror do
|
35
|
-
@onerror_handler.call(@ws) if @onerror_handler
|
13
|
+
EventMachine::WebSocket.start(:host => host,:port => port,:debug => @debug) do |ws|
|
14
|
+
#A WebSocketHandler:Connection gets passed to all callbacks
|
15
|
+
dd_conn = Connection.new(ws)
|
16
|
+
|
17
|
+
ws.onopen { @onopen_handler.call(dd_conn) if @onopen_handler }
|
18
|
+
ws.onclose { @onclose_handler.call(dd_conn) if @onclose_handler }
|
19
|
+
ws.onerror { @onerror_handler.call(dd_conn) if @onerror_handler }
|
20
|
+
|
21
|
+
ws.onmessage do |message|
|
22
|
+
if @onmessage_handler
|
23
|
+
begin
|
24
|
+
message = DripDrop::Message.decode_json(message) unless @raw
|
25
|
+
rescue StandardError => e
|
26
|
+
puts "Could not parse message: #{e.message}"
|
36
27
|
end
|
28
|
+
|
29
|
+
@onmessage_handler.call(message,dd_conn)
|
37
30
|
end
|
31
|
+
end
|
38
32
|
end
|
39
33
|
end
|
40
34
|
|
@@ -65,4 +59,17 @@ class DripDrop
|
|
65
59
|
self
|
66
60
|
end
|
67
61
|
end
|
62
|
+
|
63
|
+
class WebSocketHandler::Connection < BaseHandler
|
64
|
+
attr_reader :ws, :signature, :handler
|
65
|
+
|
66
|
+
def initialize(ws)
|
67
|
+
@ws = ws
|
68
|
+
@signature = @ws.signature
|
69
|
+
end
|
70
|
+
|
71
|
+
def send_message(message)
|
72
|
+
@ws.send(dd_messagify(message).to_hash.to_json)
|
73
|
+
end
|
74
|
+
end
|
68
75
|
end
|
@@ -8,11 +8,12 @@ class DripDrop
|
|
8
8
|
DripDrop.default_message_class = DripDrop::Message
|
9
9
|
end
|
10
10
|
|
11
|
-
class ZMQBaseHandler
|
11
|
+
class ZMQBaseHandler < BaseHandler
|
12
12
|
attr_reader :address, :socket_ctype, :socket
|
13
13
|
|
14
|
-
def initialize(
|
15
|
-
@
|
14
|
+
def initialize(zaddress,zm_reactor,socket_ctype,opts={})
|
15
|
+
@zaddress = zaddress
|
16
|
+
@address = @zaddress.to_s
|
16
17
|
@zm_reactor = zm_reactor
|
17
18
|
@socket_ctype = socket_ctype # :bind or :connect
|
18
19
|
@debug = opts[:debug] # TODO: Start actually using this
|
@@ -22,9 +23,9 @@ class DripDrop
|
|
22
23
|
def on_attach(socket)
|
23
24
|
@socket = socket
|
24
25
|
if @socket_ctype == :bind
|
25
|
-
socket.bind(@
|
26
|
+
socket.bind(@zaddress)
|
26
27
|
elsif @socket_ctype == :connect
|
27
|
-
socket.connect(@
|
28
|
+
socket.connect(@zaddress)
|
28
29
|
else
|
29
30
|
raise "Unsupported socket ctype '#{@socket_ctype}'. Expected :bind or :connect"
|
30
31
|
end
|
@@ -35,20 +36,6 @@ class DripDrop
|
|
35
36
|
@recv_cbak = block
|
36
37
|
self
|
37
38
|
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
# Normalize Hash objs and DripDrop::Message objs into DripDrop::Message objs
|
42
|
-
def dd_messagify(message)
|
43
|
-
if message.is_a?(Hash)
|
44
|
-
return DripDrop::Message.new(message[:name], :head => message[:head],
|
45
|
-
:body => message[:body])
|
46
|
-
elsif message.is_a?(DripDrop::Message)
|
47
|
-
return message
|
48
|
-
else
|
49
|
-
return message
|
50
|
-
end
|
51
|
-
end
|
52
39
|
end
|
53
40
|
|
54
41
|
module ZMQWritableHandler
|
@@ -127,8 +114,12 @@ class DripDrop
|
|
127
114
|
class ZMQSubHandler < ZMQBaseHandler
|
128
115
|
include ZMQReadableHandler
|
129
116
|
|
130
|
-
attr_reader :address, :socket_ctype
|
131
117
|
attr_accessor :topic_filter
|
118
|
+
|
119
|
+
def initialize(*args)
|
120
|
+
super(*args)
|
121
|
+
self.topic_filter = @opts[:topic_filter]
|
122
|
+
end
|
132
123
|
|
133
124
|
def on_attach(socket)
|
134
125
|
super(socket)
|
@@ -187,10 +178,11 @@ class DripDrop
|
|
187
178
|
def on_readable(socket,messages)
|
188
179
|
if @msg_format == :dripdrop
|
189
180
|
identities = messages[0..-2].map {|m| m.copy_out_string}
|
190
|
-
body
|
191
|
-
message
|
192
|
-
seq
|
193
|
-
|
181
|
+
body = messages.last.copy_out_string
|
182
|
+
message = decode_message(body)
|
183
|
+
seq = message.head['_dripdrop/x_seq_counter']
|
184
|
+
response = ZMQXRepHandler::Response.new(self, identities,seq)
|
185
|
+
@recv_cbak.call(message,response)
|
194
186
|
else
|
195
187
|
super(socket,messages)
|
196
188
|
end
|
@@ -205,6 +197,20 @@ class DripDrop
|
|
205
197
|
end
|
206
198
|
end
|
207
199
|
end
|
200
|
+
|
201
|
+
class ZMQXRepHandler::Response
|
202
|
+
attr_accessor :xrep, :seq, :identities
|
203
|
+
|
204
|
+
def initialize(xrep,identities,seq)
|
205
|
+
@xrep = xrep
|
206
|
+
@seq = seq
|
207
|
+
@identities = identities
|
208
|
+
end
|
209
|
+
|
210
|
+
def send_message(message)
|
211
|
+
@xrep.send_message(message,identities,seq)
|
212
|
+
end
|
213
|
+
end
|
208
214
|
|
209
215
|
class ZMQXReqHandler < ZMQBaseHandler
|
210
216
|
include ZMQWritableHandler
|
data/lib/dripdrop/message.rb
CHANGED
@@ -97,6 +97,11 @@ class DripDrop
|
|
97
97
|
puts "Could not parse msg '#{str}': #{e.message}"
|
98
98
|
return nil
|
99
99
|
end
|
100
|
+
|
101
|
+
# Keep this consistent
|
102
|
+
json_hash['head'][:msg_class] = json_hash['head'][:msg_class]
|
103
|
+
json_hash['head'].delete('msg_class')
|
104
|
+
|
100
105
|
self.new(json_hash['name'], :head => json_hash['head'], :body => json_hash['body'])
|
101
106
|
end
|
102
107
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class DripDrop::Node
|
2
|
+
# See the documentation for +nodelet+ in DripDrop::Node
|
3
|
+
class Nodelet
|
4
|
+
attr_accessor :name, :routing
|
5
|
+
|
6
|
+
def initialize(name, routes)
|
7
|
+
@name = name
|
8
|
+
@routing = {}
|
9
|
+
routes.each do |route_name,handler|
|
10
|
+
# Copy the original routing table
|
11
|
+
route route_name, handler
|
12
|
+
|
13
|
+
# Define short versions of the local routes for
|
14
|
+
# this nodelet's routing table
|
15
|
+
if (route_name.to_s =~ /^#{name}_(.+)$/)
|
16
|
+
short_name = $1
|
17
|
+
route short_name, handler
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def route(name,handler)
|
23
|
+
@routing[name] = handler
|
24
|
+
(class << self; self; end).class_eval do
|
25
|
+
define_method(name) { handler }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|