Collection.prototype.find = function() { var args = Array.prototype.slice.call(arguments); var oncursor = common.future(); var oncollection = this._oncollection; // we provide sugar for doing find(query, callback) -> find(query).toArray(callback); if (typeof args[args.length - 1] === 'function') { var callback = args.pop(); oncursor.get(common.fork(callback, function(cur) { cur.toArray(callback); })); } common.step([ function(next) { oncollection.get(next); }, function(col, next) { args.push(next); col.find.apply(col, args); }, function(cur) { oncursor.put(null, cur); } ], oncursor.put); return new Cursor(oncursor); };
that.collection = function(name) { var oncollection = common.future(); common.step([ function(next) { ondb.get(next); }, function(db, next) { db.collection(name, next); }, function(col) { oncollection.put(null, col); } ], oncollection.put); return new Collection(oncollection); };
var Request = common.emitter(function(method, options) { this.readable = true; this.writable = true; this._lib = options.protocol === 'https:' ? https : http; this._options = { method:method, host:options.hostname, port:options.port }; this._allowed = []; this._follow = true; this._head = false; this._piping = false; this._checkStatus = true; this._headers = {}; this._path = options.pathname || '/'; this._query = options.search || ''; this._req = null; this._onresponse = common.future(); });
exports.connect = function(url, collections) { url = parse(url); var that = {}; var ondb = common.future(); common.step([ function(next) { var client = new mongo.Db(url.db, new mongo.Server(url.host, url.port, { auto_reconnect: true })); that.bson = { Long: client.bson_serializer.Long, ObjectID: client.bson_serializer.ObjectID, Timestamp: client.bson_serializer.Timestamp, DBRef: client.bson_serializer.DBRef, Binary: client.bson_serializer.Binary, Code: client.bson_serializer.Code }; client.open(next); }, function(db, next) { this.db = db; if (url.username) { db.authenticate(url.username, url.password, next); } else { next(null, true); } }, function(success) { if (!success) { ondb.put(new Error('invalid username or password')); return; } ondb.put(null, this.db); } ], ondb.put); that.ObjectId = createObjectId; that.collection = function(name) { var oncollection = common.future(); common.step([ function(next) { ondb.get(next); }, function(db, next) { db.collection(name, next); }, function(col) { oncollection.put(null, col); } ], oncollection.put); return new Collection(oncollection); }; Object.keys(mongo.Db.prototype) .forEach(function(name) { if (!that[name] && typeof mongo.Db.prototype[name] === 'function') { that[name] = function() { var args = arguments; var callback = args[args.length - 1] || noop; ondb.get(common.fork(callback, function(db) { db[name].apply(db, args); })); }; } }); if (collections) { collections.forEach(function(col) { that[col] = that.collection(col); }); } if (typeof Proxy !== 'undefined') { return Proxy.create({ get: function(proxy, name) { if (!that[name]) { that[name] = that.collection(name); } return that[name]; } }); } return that; };
var listen = function(options) { var that = common.createEmitter(); var app = root(); var id = process.pid.toString(16)+Math.random().toString(16).substr(2); var heartbeat; var onmonitor = common.future(); var monitor = function(message) { onmonitor.get(function(err, daemon) { if (!daemon || !daemon.writable) return; daemon.write(JSON.stringify(message)+'\n'); }); }; startMonitor(onmonitor.put); var cache = {}; var own = new Repository(id); var repos = {me:own}; var proxy = function(repo) { repo.on('push', function(key, values) { cache = {}; values.forEach(function(val) { that.emit('push', key, val); }); }); repo.on('pop', function(key, values) { values.forEach(function(val) { that.emit('pop', key, val); }); }); }; var repository = function(uri) { var repo = repos[uri]; if (repo) return repo; monitor({up:uri}); repo = repos[uri] = new Repository(uri); repo.on('destroy', function() { cache = {}; delete repos[uri]; monitor({down:uri}); }); proxy(repo); return repo; }; var gc = function() { remote(function(repo) { request({ uri: repo.uri+'/ping', json: true, timeout: PING_TIMEOUT }, onresponse(repo)); }); clearTimeout(heartbeat); heartbeat = setTimeout(gc, HEARTBEAT); }; var onresponse = function(repo) { return function(err, res, body) { if (!err && res.statusCode === 200 && body.ack) return; repo.destroy(); }; }; var remote = function(fn) { Object.keys(repos).forEach(function(uri) { if (uri === 'me') return; fn(repos[uri]); }); }; proxy(own); own.on('push', function(key, values) { cache = {}; remote(function(repo) { request.post({ uri: repo.uri+'/data/'+key, headers: {'x-repository': repo.uri}, json: true, body: values }, onresponse(repo)); }); }); app.use(root.json); app.get('/'+id, function(req, res) { res.json(own); }); app.get('/'+id+'/ping', function(req, res) { res.json({ack:true}); }); app.post('/'+id+'/gc', function(req, res) { gc(); res.json({ack:true}); }); app.post('/'+id+'/data/:key', function(req, res) { var repo = repository(req.headers['x-repository'] || own.uri); repo.push(req.params.key, req.json); res.json({ack:true}); }); app.listen(function(addr, server) { own.uri = 'http://'+ME+':'+server.address().port+'/'+id; gc(); announce(own.uri, options, function(uri) { request({ uri: uri, json: true }, function(err, res, body) { if (err || res.statusCode !== 200) return; repository(uri).pushAll(body); gc(); }); }); }); that.address = ME; that.push = function(key, val) { own.push(key, val); }; that.get = function(key) { if (cache[key]) return cache[key]; var list = cache[key] = []; Object.keys(repos).forEach(function(uri) { Array.prototype.push.apply(list, repos[uri].get(key)); }); return list; }; that.all = function() { if (cache._all) return cache._all; var all = cache._all = {}; Object.keys(repos).forEach(function(uri) { var repo = repos[uri]; repo.keys().forEach(function(key) { Array.prototype.push.apply(all[key] = all[key] || [], repo.get(key)); }); }); return all; }; return that; };
var connect = function(url, collections) { var that = {}; var options = parseOptions(url); var ondb = common.future(); options.collections = options.collections || collections || []; common.step([ function(next) { var replSet = options.replSet && new mongo.ReplSetServers(options.replSet.members.map(function(member) { return new mongo.Server(member.host, member.port, {auto_reconnect:true}); }), { read_secondary:options.replSet.slaveOk, rs_name:options.replSet.name }); var client = new mongo.Db(options.db, replSet || new mongo.Server(options.host, options.port, {auto_reconnect:true}), {safe:false}); that.client = client; that.bson = { Long: client.bson_serializer.Long, ObjectID: client.bson_serializer.ObjectID, Timestamp: client.bson_serializer.Timestamp, DBRef: client.bson_serializer.DBRef, Binary: client.bson_serializer.Binary, Code: client.bson_serializer.Code }; client.open(next); }, function(db, next) { this.db = db; if (url.username) { db.authenticate(url.username, url.password, next); } else { next(null, true); } }, function(success) { if (!success) { ondb.put(new Error('invalid username or password')); return; } ondb.put(null, this.db); } ], ondb.put); that.ObjectId = createObjectId; that.collection = function(name) { var oncollection = common.future(); common.step([ function(next) { ondb.get(next); }, function(db, next) { db.collection(name, next); }, function(col) { oncollection.put(null, col); } ], oncollection.put); return new Collection(oncollection); }; Object.keys(mongo.Db.prototype).forEach(function(name) { if (shouldExtend(that, mongo.Db.prototype, name)) { that[name] = function() { var args = arguments; var callback = args[args.length-1] || noop; ondb.get(common.fork(callback, function(db) { db[name].apply(db, args); })); }; } }); if (collections) { collections.forEach(function(col) { that[col] = that.collection(col); }); } if (typeof Proxy !== 'undefined') { return Proxy.create({ get: function(proxy, name) { if (!that[name]) { that[name] = that.collection(name); } return that[name]; } }); } return that; };
exports.connect = function(url, collections) { url = parse(url); var that = {}; var ondb = common.future(); common.step([ function(next) { var client = new mongo.Db(url.db, new mongo.Server(url.host, url.port), {native_parser:true}); that.bson = { Long: client.bson_serializer.Long, ObjectID: client.bson_serializer.ObjectID, Timestamp: client.bson_serializer.Timestamp, DBRef: client.bson_serializer.DBRef, Binary: client.bson_serializer.Binary, Code: client.bson_serializer.Code }; client.open(next); }, function(db, next) { this.db = db; if (url.username) { db.authenticate(url.username, url.password, next); } else { next(null, true); } }, function(success) { if (!success) { ondb.put(new Error('invalid username or password')); return; } ondb.put(null, this.db); } ], ondb.put); that.close = function(callback) { callback = callback || noop; ondb.get(common.fork(callback, function(db) { db.close(callback); })); }; that.collection = function(name) { var oncollection = common.future(); common.step([ function(next) { ondb.get(next); }, function(db, next) { db.collection(name, next); }, function(col) { oncollection.put(null, col); } ], oncollection.put); return new Collection(oncollection); }; if (collections) { collections.forEach(function(col) { that[col] = that.collection(col); }); } if (typeof Proxy !== 'undefined') { return Proxy.create({ get: function(proxy, name) { if (!that[name]) { that[name] = that.collection(name); } return that[name]; } }); } return that; };
var Peer = common.emitter(function(hub, socket) { var self = this; var types = {}; this.address = null; this.onconnect = common.future(); if (typeof socket === 'string') { this.address = socket; this.onconnect.put(this.address); socket = sockets.connect(socket); socket.send({type:'connect', from:hub.address, nodes:hub.nodes()}); } this.callbacks = {}; this.multiplexes = {}; this.writable = this.readable = true; this.socket = socket; this.hub = hub; types.connect = function(message) { socket.send({type:'nodes', nodes:hub.nodes()}); self.address = message.from; self.emit('connect', message.from); if (message.nodes.length) { self.emit('nodes', message.nodes); } self.onconnect.put(self.address); }; types.nodes = function(message) { self.emit('nodes', message.nodes); }; types.multiplex = function(message, callback) { var multiplexed = !!self.multiplexes[message.channel]; if (multiplexed) { self.emit('multiplex', message.channel); } callback(null, multiplexed); }; types.response = function(message) { (self.callbacks[message.id] || noop)(message.error && new Error(message.error), message.data); }; types.message = function(message, callback) { self.emit('message', message, callback); }; socket.on('close', function() { self.writable = self.readable = false; self.emit('close'); if (self.address) { self.emit('disconnect', self.address); } for (var i in self.callbacks) { self.callbacks[i](new Error('node failure')); } }); socket.on('message', function(message) { (types[message.type] || types.message)(message, !message.id ? noop : function(err, data) { socket.send({id:message.id, type:'response', error:(err && err.message), data:data}); }); }); });
exports.create = function(proxy) { var that = {}; var onframe = common.future(); var iframe = document.createElement('iframe'); iframe.style.position = 'absolute'; iframe.style.left = '-1000px'; iframe.style.top = '-1000px'; iframe.style.visibility = 'hidden'; iframe.src = proxy; var onbody = function() { document.body.appendChild(iframe); }; if (document.body) { onbody(); } else { onevent('load', onbody); } var onmessage = function(event) { onframe.put(iframe.contentWindow); onmessage = function(event) { var data; try { data = JSON.parse(event.data); } catch (ex) { data = {}; } var callback = callbacks[data.id]; if (!callback) { return; } delete callbacks[data.id]; callback(data.err && new Error(data.err), data.value); }; }; var callbacks = {}; onevent('message', function(event) { if (proxy.indexOf(event.origin) !== 0) { return; } onmessage(event); }); /* Sends message to the iFrame. Callback is invoked, when the iFrame responds. */ var send = function(message, callback) { var id = common.gensym(); callbacks[id] = callback; message.id = id; onframe.get(function(frame) { frame.postMessage(JSON.stringify(message), proxy); }); }; /* Send a cross-origin xhr request. Arguments: service : The request is sent to the url: domain/service, where domain is the domain on which the proxy is served. settings : Same as in jQuery-1.6.2's $.ajax() method. */ that.ajax = function() { var callbacks = { }; return function(service, settings) { var id = common.gensym(); callbacks[id] = { success : settings.success, error : settings.error, complete : settings.complete }; send({ service : service, settings : settings}, function(err, result) { var callback = callbacks[id]; delete callbacks[id]; if(err && typeof(callback.error) === "function") { callback.error(result.xhr, result.status, result.xhr.status); } else if(typeof(callback.success) === "function") { callback.success(result.xhr.responseText); } if(typeof(callback.complete) === "function") { callback.complete(result.xhr, result.status); } }); } }(); that.destroy = function() { onframe.get(function() { iframe.parentNode.removeChild(iframe); }); }; return that; };