Comparing version 0.2.3 to 0.3.0
@@ -1,17 +0,41 @@ | ||
var DDPClient = require("../lib/ddp-client"); | ||
var DDPClient = require("../lib/ddp-client"); | ||
var ddpclient = new DDPClient({host: "localhost", port: 3000}); | ||
var ddpclient = new DDPClient({ | ||
host: "localhost", | ||
port: 3000, | ||
/* optional: */ | ||
auto_reconnect: true, | ||
auto_reconnect_timer: 500 | ||
}); | ||
ddpclient.connect(function() { | ||
console.log('connected!'); | ||
ddpclient.call('test-function', ['foo', 'bar'], function(err, result) { | ||
console.log('called function, result: ' + result); | ||
}) | ||
}); | ||
ddpclient.subscribe('posts', [], function() { | ||
console.log('posts complete:'); | ||
console.log(ddpclient.collections.posts); | ||
}) | ||
}); | ||
}); | ||
/* | ||
* Useful for debugging and learning the ddp protocol | ||
*/ | ||
ddpclient.on('message', function(msg) { | ||
console.log("ddp message: " + msg); | ||
}); | ||
/* | ||
* If you need to do something specific on close or errors. | ||
* You can also disable auto_reconnect and | ||
* call ddpclient.connect() when you are ready to re-connect. | ||
*/ | ||
ddpclient.on('socket-close', function(code, message) { | ||
console.log("Close: %s %s", code, message); | ||
}); | ||
ddpclient.on('socket-error', function(error) { | ||
console.log("Error: %j", error); | ||
}); |
@@ -1,7 +0,9 @@ | ||
var WebSocket = require('ws'); | ||
var _ = require('underscore'); | ||
var WebSocket = require('ws'), | ||
_ = require('underscore'), | ||
util = require('util'), | ||
events = require('events'); | ||
DDPClient = function(opts) { | ||
var self = this; | ||
// default arguments | ||
@@ -12,32 +14,67 @@ self.host = opts.host || 'localhost'; | ||
self.use_ssl = opts.use_ssl || self.port === 443; | ||
self.auto_reconnect = ('auto_reconnect' in opts) ? opts.auto_reconnect : true; | ||
self.auto_reconnect_timer = ('auto_reconnect_timer' in opts) ? opts.auto_reconnect_timer : 500; | ||
// very very simple collections (name -> [{id -> document}]) | ||
self.collections = {}; | ||
// internal stuff to track callbacks | ||
self._next_id = 0; | ||
self._callbacks = {}; | ||
} | ||
}; | ||
/** | ||
* Inherits from EventEmitter | ||
*/ | ||
util.inherits(DDPClient, events.EventEmitter); | ||
DDPClient.prototype._prepareHandlers = function() { | ||
var self = this; | ||
// just go ahead and open the connection on connect | ||
self.socket.on('open', function() { | ||
self._send({msg: 'connect'}); | ||
// just go ahead and open the connection on connect | ||
var connectionPayload = { | ||
msg: 'connect', | ||
version: 'pre1', | ||
support: ['pre1'] | ||
}; | ||
// if reconnecting, try existing DDP session | ||
// removed for now, per conversatino with sixolet on IRC, | ||
// reconnect on server side still needs work | ||
/* | ||
if (self.session) connectionPayload.session = self.session; | ||
*/ | ||
self._send(connectionPayload); | ||
}); | ||
// all messages go to the handler | ||
self.socket.on('error', function(error) { | ||
self.emit('socket-error', error); | ||
if (self.auto_reconnect) { | ||
setTimeout(function() { self.connect(); }, self.auto_reconnect_timer); | ||
} | ||
}); | ||
self.socket.on('close', function(code, message) { | ||
self.emit('socket-close', code, message); | ||
if (self.auto_reconnect) { | ||
setTimeout(function() { self.connect(); }, self.auto_reconnect_timer); | ||
} | ||
}); | ||
self.socket.on('message', function(data, flags) { | ||
self.emit('message', data, flags); | ||
self._message(data, flags); | ||
}); | ||
} | ||
}; | ||
/////////////////////////////////////////////////////////////////////////// | ||
// RAW, low level functions | ||
DDPClient.prototype._send = function(data) { | ||
this.socket.send(JSON.stringify(data)); | ||
} | ||
}; | ||
@@ -47,95 +84,119 @@ // handle a message from the server | ||
var self = this; | ||
// TODO: EJSON parsing | ||
var data = JSON.parse(data); | ||
// TODO: 'error' | ||
// TODO -- method acks <- not sure exactly what the point is here | ||
// TODO: 'updated' -- not sure exactly what the point is here | ||
// TODO: 'addedBefore' -- not yet implemented in Meteor | ||
// TODO: 'movedBefore' -- not yet implemented in Meteor | ||
if (!data.msg) { | ||
return; | ||
} else if (data.msg === 'connected') { | ||
if (self._callbacks.connected) | ||
self._callbacks.connected(); | ||
self.session = data.session; | ||
self.emit('connected'); | ||
// method result | ||
} else if (data.msg === 'result') { | ||
var cb = self._callbacks[data.id]; | ||
if (cb) { | ||
cb(data.error, data.result); | ||
delete self._callbacks[data.id] | ||
delete self._callbacks[data.id]; | ||
} | ||
// missing subscription | ||
} else if (data.msg === 'nosub') { | ||
var cb = self._callbacks[data.id]; | ||
if (cb) { | ||
cb(data.error); | ||
delete self._callbacks[data.id] | ||
delete self._callbacks[data.id]; | ||
} | ||
} else if (data.msg === 'data') { | ||
// add document to collection | ||
} else if (data.msg === 'added') { | ||
if (data.collection) { | ||
self._updateCollection(data); | ||
// subscription complete | ||
} else if (data.subs) { | ||
_.each(data.subs, function(id) { | ||
var cb = self._callbacks[id]; | ||
if (cb) { | ||
cb(); | ||
delete self._callbacks[id] | ||
} | ||
}); | ||
var name = data.collection, id = data.id; | ||
if (!self.collections[name]) | ||
self.collections[name] = {}; | ||
if (!self.collections[name][id]) | ||
self.collections[name][id] = {}; | ||
if (data.fields) { | ||
_.each(data.fields, function(value, key) { | ||
self.collections[name][id][key] = value; | ||
}); | ||
} | ||
} | ||
// remove document from collection | ||
} else if (data.msg === 'removed') { | ||
if (data.collection) { | ||
var name = data.collection, id = data.id; | ||
if (!self.collections[name][id]) | ||
return; | ||
delete self.collections[name][id]; | ||
} | ||
// change document in collection | ||
} else if (data.msg === 'changed') { | ||
if (data.collection) { | ||
var name = data.collection, id = data.id; | ||
if (!self.collections[name]) return; | ||
if (!self.collections[name][id]) return; | ||
if (data.fields) { | ||
_.each(data.fields, function(value, key) { | ||
self.collections[name][id][key] = value; | ||
}); | ||
} | ||
if (data.cleared) { | ||
_.each(data.cleared, function(value) { | ||
delete self.collections[name][id][value]; | ||
}); | ||
} | ||
} | ||
// subscriptions ready | ||
} else if (data.msg === 'ready') { | ||
_.each(data.subs, function(id) { | ||
var cb = self._callbacks[id]; | ||
if (cb) { | ||
cb(); | ||
delete self._callbacks[id]; | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
DDPClient.prototype._nextId = function() { | ||
return (this._next_id += 1).toString(); | ||
} | ||
}; | ||
DDPClient.prototype._updateCollection = function(data) { | ||
var self = this; | ||
var name = data.collection, id = data.id; | ||
if (!self.collections[name]) | ||
self.collections[name] = {}; | ||
if (!self.collections[name][id]) | ||
self.collections[name][id] = {} | ||
if (data.set) { | ||
_.each(data.set, function(value, key) { | ||
self.collections[name][id][key] = value; | ||
}); | ||
} | ||
if (data.unset) { | ||
_.each(data.unset, function(value) { | ||
delete self.collections[name][id][value]; | ||
}); | ||
} | ||
// clean up | ||
if (_.isEmpty(self.collections[name][id])) | ||
delete self.collections[name][id]; | ||
} | ||
////////////////////////////////////////////////////////////////////////// | ||
// USER functions -- use these to control the client | ||
// open the connection to the server | ||
DDPClient.prototype.connect = function(callback) { | ||
/* open the connection to the server | ||
* | ||
* connected(): Called when the 'connected' message is received | ||
* If auto_reconnect is true (default), the callback will be | ||
* called each time the connection is opened. | ||
*/ | ||
DDPClient.prototype.connect = function(connected) { | ||
var self = this; | ||
if (callback) | ||
self._callbacks.connected = callback; | ||
if (connected) | ||
self.addListener("connected", connected); | ||
// websocket | ||
@@ -145,9 +206,9 @@ var protocol = self.use_ssl ? 'wss://' : 'ws://'; | ||
self._prepareHandlers(); | ||
} | ||
}; | ||
DDPClient.prototype.close = function() { | ||
var self = this; | ||
self.socket.close(); | ||
} | ||
}; | ||
@@ -159,9 +220,9 @@ // call a method on the server, | ||
var self = this; | ||
var id = self._nextId() | ||
var id = self._nextId(); | ||
if (callback) | ||
self._callbacks[id] = callback; | ||
self._send({msg: 'method', id: id, method: name, params: params}); | ||
} | ||
}; | ||
@@ -171,10 +232,16 @@ // open a subscription on the server, callback should handle on ready and nosub | ||
var self = this; | ||
var id = self._nextId() | ||
var id = self._nextId(); | ||
if (callback) | ||
self._callbacks[id] = callback; | ||
self._send({msg: 'sub', id: id, name: name, params: params}); | ||
} | ||
}; | ||
module.exports = DDPClient; | ||
DDPClient.prototype.unsubscribe = function(id) { | ||
var self = this; | ||
self._send({msg: 'unsub', id: id}); | ||
}; | ||
module.exports = DDPClient; |
{ | ||
"name": "ddp", | ||
"version": "0.2.3", | ||
"version": "0.3.0", | ||
"description": "Node.js module to connect to servers using DDP protocol.", | ||
@@ -5,0 +5,0 @@ "author": "Tom Coleman <tom@thesnail.org> (http://tom.thesnail.org), Mike Bannister <notimpossiblemike@gmail.com> (http://po.ssibiliti.es)", |
Sorry, the diff of this file is not supported yet
9739
6
221
84