Skip to content

Commit

Permalink
socket.io examples work with the new callback stuff now
Browse files Browse the repository at this point in the history
  • Loading branch information
James Halliday committed Jul 10, 2010
1 parent e743e0b commit 31c9ce9
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 111 deletions.
92 changes: 0 additions & 92 deletions dnode-client.js

This file was deleted.

4 changes: 2 additions & 2 deletions examples/simple.js
Expand Up @@ -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);

Expand Down
5 changes: 2 additions & 3 deletions 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);
Expand Down
24 changes: 12 additions & 12 deletions 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' });
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion lib/dnode.js
Expand Up @@ -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,
});
Expand Down
3 changes: 2 additions & 1 deletion 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;
Expand All @@ -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],
});
Expand Down
86 changes: 86 additions & 0 deletions 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));
};
};

44 changes: 44 additions & 0 deletions 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;
};
}
72 changes: 72 additions & 0 deletions 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.