diff --git a/app/meteor/skel/.meteor/packages b/app/meteor/skel/.meteor/packages index 301b942bde..12c5f051c0 100644 --- a/app/meteor/skel/.meteor/packages +++ b/app/meteor/skel/.meteor/packages @@ -2,3 +2,5 @@ # # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. + +autopublish diff --git a/packages/autopublish/autopublish.js b/packages/autopublish/autopublish.js new file mode 100644 index 0000000000..f375450b3b --- /dev/null +++ b/packages/autopublish/autopublish.js @@ -0,0 +1 @@ +App._enable_autopublish(); \ No newline at end of file diff --git a/packages/autopublish/package.js b/packages/autopublish/package.js new file mode 100644 index 0000000000..7833caae42 --- /dev/null +++ b/packages/autopublish/package.js @@ -0,0 +1,8 @@ +Package.describe({ + summary: "Automatically publish all data in the database to every client" +}); + +Package.on_use(function (api, where) { + api.use('livedata', 'server'); + api.add_files("autopublish.js", "server"); +}); \ No newline at end of file diff --git a/packages/livedata/collection.js b/packages/livedata/collection.js index 3f0d776bec..be0ceb750e 100644 --- a/packages/livedata/collection.js +++ b/packages/livedata/collection.js @@ -73,6 +73,7 @@ Meteor.Collection = function (name, manager, driver) { throw new Error("There is already a collection named '" + name + "'"); } + // mutation methods if (manager) { var m = {}; // XXX what if name has illegal characters in it? @@ -96,8 +97,17 @@ Meteor.Collection = function (name, manager, driver) { } // XXX temporary hack to provide sugar in LivedataServer.publish() - if (name && manager && manager._hack_collections) + if (name && manager && manager._hack_collections) { + if (name in manager._hack_collections) + throw new Error("There is already a collection named '" + name + "'"); manager._hack_collections[name] = self; + } + + // autopublish + if (name && manager.onAutopublish) + manager.onAutopublish(function () { + manager.publish(name, {is_auto: true}); + }); }; diff --git a/packages/livedata/livedata_server.js b/packages/livedata/livedata_server.js index 33fd0b06a4..3c5f1cfd26 100644 --- a/packages/livedata/livedata_server.js +++ b/packages/livedata/livedata_server.js @@ -7,6 +7,8 @@ Meteor._LivedataServer = function () { self._hack_collections = {}; // XXX hack. name => Collection self.method_handlers = {}; self.stream_server = new Meteor._StreamServer; + self.on_autopublish = []; // array of func if AP disabled, null if enabled + self.warned_about_autopublish = false; self.stream_server.register(function (socket) { socket.meteor = {}; @@ -267,6 +269,10 @@ _.extend(Meteor._LivedataServer.prototype, { * - selector {Function OR Object} either a mongodb selector, * or a function that takes the argument object passed to * Meteor.subscribe and returns a mongodb selector. default {} + * - (mostly internal) is_auto: true if generated automatically + * from an autopublish hook. this is for cosmetic purposes only + * (it lets us determine whether to print a warning suggesting + * that you turn off autopublish.) */ publish: function (name, options) { var self = this; @@ -278,6 +284,32 @@ _.extend(Meteor._LivedataServer.prototype, { } options = options || {}; + + if (!self.onAutopublish && options.is_auto) { + // They have autopublish on, yet they're trying to manually + // picking stuff to publish. They probably should turn off + // autopublish. (This check isn't perfect -- if you create a + // publish before you turn on autopublish, it won't catch + // it. But this will definitely handle the simple case where + // you've added the autopublish package to your app, and are + // calling publish from your app code.) + if (!self.warned_about_autopublish) { + self.warned_about_autopublish = true; + Meteor._debug( +"** You've set up some data subscriptions with Meteor.publish(), but\n" + +"** you still have autopublish turned on. Because autopublish is still\n" + +"** on, your Meteor.publish() calls won't have much effect. All data\n" + +"** will still be sent to all clients.\n" + +"**\n" + +"** Turn off autopublish by removing the autopublish package:\n" + +"**\n" + +"** $ meteor remove autopublish\n" + +"**\n" + +"** .. and make sure you have a Meteor.publish() call for each\n" + +"** collection you want clients to be able to use.\n\n"); + } + } + var collection = options.collection || self._hack_collections[name]; if (!collection) throw new Error("No collection '" + name + "' found to publish. " + @@ -334,5 +366,24 @@ _.extend(Meteor._LivedataServer.prototype, { if (result_func) result_func(ret); // XXX catch exception? return ret; + }, + + // A much more elegant way to do this would be: let any autopublish + // provider (eg, mongo-livedata) declare a weak package dependency + // on the autopublish package, then have that package simply set a + // flag that eg the Collection constructor checks, and autopublishes + // if necessary. + autopublish: function () { + var self = this; + _.each(self.on_autopublish || [], function (f) { f(); }); + self.on_autopublish = null; + }, + + onAutopublish: function (f) { + var self = this; + if (self.on_autopublish) + self.on_autopublish.push(f); + else + f(); } }); diff --git a/packages/logging/logging.js b/packages/logging/logging.js index 430277f2e5..6a2dc83349 100644 --- a/packages/logging/logging.js +++ b/packages/logging/logging.js @@ -4,7 +4,14 @@ if (typeof Meteor === "undefined") Meteor = {}; // replacement for console.log. This is a temporary API. We should // provide a real logging API soon (possibly just a polyfill for // console?) - Meteor._debug = function (/* varargs */) { + // + // NOTE: this is used on the server to print the warning about + // having autopublish enabled when you probably meant to turn it + // off. it's not really the proper use of something called + // _debug. the intent is for this message to go to the terminal and + // be very visible. if you change _debug to go someplace else, etc, + // please fix the autopublish code to do something reasonable. + Meteor._debug = function (/* arguments */) { if (typeof console !== 'undefined' && typeof console.log !== 'undefined') { if (arguments.length == 0) { @@ -13,5 +20,5 @@ if (typeof Meteor === "undefined") Meteor = {}; console.log.apply(console, arguments); } } - } + }; })();