Browse files

socket.io examples work with the new callback stuff now

  • Loading branch information...
1 parent e743e0b commit 31c9ce9c111519030aa281c230b8714de2c67ab3 @substack committed Jul 10, 2010
Showing with 221 additions and 111 deletions.
  1. +0 −92 dnode-client.js
  2. +2 −2 examples/simple.js
  3. +2 −3 examples/web.html
  4. +12 −12 examples/web.js
  5. +1 −1 lib/dnode.js
  6. +2 −1 lib/socketio_conn.js
  7. +86 −0 web/dnode.js
  8. +44 −0 web/scrubber.js
  9. +72 −0 web/traverse.js
View
92 dnode-client.js
@@ -1,92 +0,0 @@
-// Client code to Connect to DNode proxies from the web browser
-function DNode (obj) {
- if (!(this instanceof DNode)) return new DNode(obj);
- var dnode = this;
- if (obj === undefined) obj = {};
-
- if (!('methods' in obj)) {
- obj.methods = function () {
- return Object.keys(obj);
- };
- }
-
- function firstType (args, type) {
- return [].concat.apply([],args).filter(function (x) {
- return typeof(x) == type
- })[0];
- }
-
- this.connect = function () {
- var kwargs = firstType(arguments,'object') || {};
- var host = firstType(arguments,'string')
- || kwargs.host || window.location.hostname;
- var port = firstType(arguments,'string')
- || kwargs.port || window.location.port;
- var block = firstType(arguments,'function') || kwargs.block;
-
- var sock = new io.Socket(host, {
- rememberTransport : kwargs.rememberTransport || false,
- transports : kwargs.transports ||
- 'websocket htmlfile xhr-multipart xhr-polling'.split(/\s+/),
- port : port,
- });
-
- var reqId = 0;
- var handlers = {};
- var remote = {};
- function request(method, args, f) {
- handlers[reqId] = f;
- sock.send(JSON.stringify({
- method : method,
- arguments : args,
- id : reqId ++,
- }));
- }
-
- sock.addEvent('connect', function () {
- request('methods', [], function (methods) {
- methods.forEach(function (method) {
- remote[method] = function () {
- var args = [].concat.apply([],arguments);
- var argv = args.slice(0,-1);
- var f = args.slice(-1)[0];
- request(method,argv,f);
- };
- });
- block.call(remote, remote, dnode);
- });
- });
-
- sock.addEvent('message', function (strMsg) {
- var msg = JSON.parse(strMsg);
- if ('result' in msg) {
- handlers[msg.id].call(remote,msg.result);
- }
- else if ('method' in msg) {
- var f = obj[msg.method];
- if (f.asynchronous) {
- var args = msg.arguments + [ function (res) {
- sock.send(JSON.stringify({
- id : msg.id,
- result : res,
- }));
- } ];
- f.apply(obj,args);
- }
- else {
- var res = f.apply(obj,msg.arguments);
- sock.send(JSON.stringify({
- id : msg.id,
- result : res,
- }));
- }
- }
- });
-
- sock.connect();
- };
-}
-
-DNode.async = function (f) {
- f.asynchronous = true;
-}
View
4 examples/simple.js
@@ -4,8 +4,8 @@ var sys = require('sys');
// server-side:
var server = DNode({
- timesTen : function (n,f) { f(n * 10) },
- moo : function (f) { f(100) },
+ timesTen : function (n,reply) { reply(n * 10) },
+ moo : function (reply) { reply(100) },
sTimesTen : DNode.sync(function (n) { return n * 10 }),
}).listen(6060);
View
5 examples/web.html
@@ -1,8 +1,7 @@
-<script type="text/javascript" src="/js/socket.io.js"></script>
-<script type="text/javascript" src="/js/dnode-client.js"></script>
+<script type="text/javascript" src="/dnode.js"></script>
<script type="text/javascript">
DNode({
- name : function () { return 'Mr. Spock' },
+ name : function (f) { f('Mr. Spock') },
}).connect(function (remote) {
remote.timesTen(10, function (n) {
document.getElementById("result").innerHTML = String(n);
View
24 examples/web.js
@@ -1,21 +1,21 @@
#!/usr/bin/env node
+// NOTE: Symlink socket.io.js into web/ first
+
var DNode = require('dnode').DNode;
var sys = require('sys');
var fs = require('fs');
var http = require('http');
var html = fs.readFileSync(__dirname + '/web.html');
-var js = {
- 'dnode-client.js' : fs.readFileSync(__dirname + '/../dnode-client.js'),
- // Symlink socket.io.js to examples/ first
- 'socket.io.js' : fs.readFileSync(__dirname + '/socket.io.js'),
-};
+var js = ['socket.io.js','traverse.js','scrubber.js','dnode.js']
+ .reduce(function (acc,file) {
+ return acc + fs.readFileSync(__dirname + '/../web/' + file);
+ }, '');
var httpServer = http.createServer(function (req,res) {
- var m = req.url.match(/^\/js\/(.+)/);
- if (m) {
+ if (req.url == '/dnode.js') {
res.writeHead(200, { 'Content-Type' : 'text/javascript' });
- res.end(js[m[1]]);
+ res.end(js);
}
else {
res.writeHead(200, { 'Content-Type' : 'text/html' });
@@ -26,16 +26,16 @@ httpServer.listen(6061);
// listen on 6060 and socket.io
DNode(function (client) {
- this.timesTen = function (n) { return n * 10 };
- this.whoAmI = DNode.async(function (f) {
+ this.timesTen = function (n,f) { f(n * 10) };
+ this.whoAmI = function (reply) {
client.name(function (name) {
- f(name
+ reply(name
.replace(/Mr\.?/,'Mister')
.replace(/Ms\.?/,'Miss')
.replace(/Mrs\.?/,'Misses')
);
})
- });
+ };
}).listen({
protocol : 'socket.io',
server : httpServer,
View
2 lib/dnode.js
@@ -65,7 +65,7 @@ function DNode (wrapper) {
var server = kwargs.server;
delete kwargs.server;
delete kwargs.protocol;
- var conn = SocketIOConn({
+ var conn = new SocketIOConn({
socketIO : io.listen(server, kwargs),
wrapper : wrapper,
});
View
3 lib/socketio_conn.js
@@ -1,5 +1,6 @@
// dnode connection module for SocketIO streams
var EventEmitter = require('events').EventEmitter;
+var Conn = require('dnode/conn').Conn;
exports.SocketIOConn = SocketIOConn;
SocketIOConn.prototype = new EventEmitter;
@@ -18,7 +19,7 @@ function SocketIOConn (params) {
sock.addListener('clientConnect', function (client) {
var id = client.sessionId;
streams[id] = new StreamIO(client);
- var conn = new DNodeConn({
+ var conn = new Conn({
wrapper : params.wrapper,
stream : streams[id],
});
View
86 web/dnode.js
@@ -0,0 +1,86 @@
+// Client code to Connect to DNode proxies from the web browser
+function DNode (obj) {
+ if (!(this instanceof DNode)) return new DNode(obj);
+ var self = this;
+ if (obj === undefined) obj = {};
+
+ function firstTypes (args) {
+ var types = {};
+ [].concat.apply([],args).forEach(function (arg) {
+ var t = typeof(arg);
+ if (!(t in types)) types[t] = arg;
+ });
+ return types;
+ }
+
+ this.connect = function () {
+ var types = firstTypes(arguments) || {};
+ var kwargs = types.object || {};
+ var host = kwargs.host || types.string || window.location.hostname;
+ kwargs.port = kwargs.port || types.number || window.location.port;
+ var block = types['function'] || kwargs.block || function () {};
+
+ delete kwargs.port;
+ delete kwargs.block;
+ kwargs.rememberTransport = kwargs.rememberTransport || false;
+ kwargs.transports = kwargs.transports
+ || 'websocket htmlfile xhr-multipart xhr-polling'.split(/\s+/);
+
+ var sock = new io.Socket(host, kwargs);
+
+ var remote = {};
+ var scrubber = new Scrubber;
+
+ function sendRequest(method, args) {
+ var scrub = scrubber.scrub(args);
+ sock.send(JSON.stringify({
+ method : method,
+ arguments : scrub.arguments,
+ callbacks : scrub.callbacks
+ }));
+ }
+
+ sock.addEvent('connect', function () {
+ sendRequest('methods', Object.keys(obj));
+ });
+
+ sock.addEvent('message', function (strMsg) {
+ var req = JSON.parse(strMsg);
+ var args = scrubber.unscrub(req, function (id) {
+ return function () {
+ sendRequest(id, [].concat.apply([],arguments));
+ };
+ });
+
+ if (req.method == 'methods') {
+ args.forEach(function (method) {
+ remote[method] = function () {
+ var argv = [].concat.apply([],arguments);
+ sendRequest(method, argv);
+ };
+ });
+ block.call(obj, remote, self);
+ }
+ else if (typeof(req.method) == 'string') {
+ obj[req.method].apply(obj,args);
+ }
+ else if (typeof(req.method) == 'number') {
+ scrubber.callbacks[req.method].apply(obj,args);
+ }
+ });
+
+ sock.connect();
+ };
+}
+
+// wrapper to turn synchronous functions into asynchronous ones with the
+// result callback inserted as the last argument
+DNode.sync = function (f) {
+ return function () {
+ var args = [].concat.apply([],arguments);
+ var argv = args.slice(0,-1);
+ var cb = args.slice(-1)[0];
+ cb(f.apply(this,argv));
+ };
+};
+
View
44 web/scrubber.js
@@ -0,0 +1,44 @@
+function Scrubber () {
+ this.callbacks = {};
+ var cbId = 0;
+ var self = this;
+
+ // Take the functions out and note them for future use
+ this.scrub = function (obj) {
+ var paths = {};
+ var args = Traverse(obj).modify(function (node) {
+ if (typeof(node) == 'function') {
+ self.callbacks[cbId] = node;
+ paths[cbId] = this.path;
+ this.update('[Function]');
+ cbId++;
+ }
+ }).get();
+ return {
+ arguments : args,
+ callbacks : paths,
+ };
+ };
+
+ // Replace callbacks. The supplied function should take a callback id and
+ // return a callback of its own.
+ this.unscrub = function (msg, f) {
+ var args = msg.arguments || [];
+ Object.keys(msg.callbacks || {}).forEach(function (strId) {
+ var id = parseInt(strId,10);
+ var path = msg.callbacks[id];
+ var node = args;
+ path.slice(0,-1).forEach(function (key) {
+ node = node[key];
+ });
+ var last = path.slice(-1)[0];
+ if (last === undefined) {
+ args = f(id);
+ }
+ else {
+ node[last] = f(id);
+ }
+ });
+ return args;
+ };
+}
View
72 web/traverse.js
@@ -0,0 +1,72 @@
+function Traverse (obj) {
+ if (!(this instanceof Traverse)) return new Traverse(obj);
+
+ this.get = function () { return obj };
+
+ this.modify = function (f) {
+ var path = [];
+ var parents = [];
+ walk(obj);
+ return this;
+
+ function walk (node) {
+ var state = {
+ node : node,
+ path : [].concat(path),
+ parent : parents.slice(-1)[0],
+ key : path.slice(-1)[0],
+ isRoot : node == obj,
+ notRoot : node != obj,
+ isLeaf : typeof(node) != 'object'
+ || Object.keys(node).length == 0,
+ notLeaf : typeof(node) == 'object'
+ && Object.keys(node).length > 0,
+ update : function (x) {
+ if (state.isRoot) {
+ obj = x;
+ }
+ else {
+ state.parent.node[state.key] = x;
+ }
+ state.node = x;
+ },
+ level : path.length,
+ };
+
+ f.call(state, node);
+ if (typeof(state.node) == 'object') {
+ parents.push(state);
+ Object.keys(state.node).forEach(function (key) {
+ path.push(key);
+ walk(state.node[key]);
+ path.pop();
+ });
+ parents.pop();
+ }
+ }
+ };
+
+ this.forEach = function (f) {
+ this.modify(function (node) {
+ delete this.update;
+ f.call(this,node);
+ },null);
+ return this;
+ };
+
+ this.paths = function () {
+ var acc = [];
+ this.each(function (x) {
+ acc.push(this.path);
+ });
+ return acc;
+ };
+
+ this.nodes = function () {
+ var acc = [];
+ this.each(function (x) {
+ acc.push(this.node);
+ });
+ return acc;
+ };
+}

0 comments on commit 31c9ce9

Please sign in to comment.