/** * Lens.Central handles communication with this devices Lens Central server. * * @namespace * @name Lens.Central */ define(["lib/underscore", "ARCore/db", "common/util/check", "lib/meteor", "cgi-bin/configuration"], function(_, DB, check, meteor, Configuration) { "use strict"; var States, Events; var now = function() { return (new Date()).getTime(); }; var DEFAULT_GROUP = "Default"; var Meteor = meteor.meteor.Meteor; var DDP = meteor.livedata.DDP; var Accounts = meteor["accounts-base"].Accounts; window.Meteor = Meteor; // connects Meteor to a backend, using that as the default backend var connectAsDefault = function(url) { if(Meteor.connection) { Meteor.connection.disconnect(); } Meteor.connection = DDP.connect(url); // Accounts keeps its own pointer to the current connection. Accounts.connection = Meteor.connection; // We need to re-connect Meteor.users using the new connection Meteor.users = new Meteor.Collection("users"); // Proxy the public methods of Meteor.connection so they can // be called directly on Meteor, which Meteor's accounts system does. _.each(["subscribe", "methods", "call", "apply", "status", "reconnect", "disconnect"], function (name) { Meteor[name] = _.bind(Meteor.connection[name], Meteor.connection); }); }; /** * @privconstructor * @class * Tracks the state of a user and logs it to the Lens Central server. * * @name StateTracker */ var StateTracker = function(group) { /** @alias StateTracker.prototype */ var self = {}; var stateId = null; /** * Sets the user's state. This ends the state previously set by this * StateTracker, but not states set by other StateTrackers, so users * can be in multiple states at the same time, but a StateTracker can * only track on state at a time. * * @param {String} newState The name of the new state. * @param {Any} [data] Arbitrary data to associate with the state. * Must be JSON-serializable. */ self.setState = function(newState, data) { check(newState, String); check(data, check.Match.Optional(check.Match.Serializable)); // end the previous state self.endState(); // start a new state stateId = States.insert({ user: Meteor.userId(), name: newState, prevState: stateId, data: data, startTime: now(), group: group }); }; /** * Ends the states previously set by this StateTracker without starting * a new state. */ self.endState = function() { if(stateId) { States.update({_id: stateId}, {$set: { endTime: now() }}); } stateId = null; }; Object.freeze(self); return self; }; var Central = /** @lends Lens.Central */ { /** * Connects to a new Lens Central server (disconnecting from the * previous one, if there is one). You don't typically need to * call this; Lens will automatically connect to the Lens Central * server set in the configuration variable `lens.central_url` * * @param {String} url The URL of the server, e.g. "localhost:3434" or * "central.mycompany.com" */ connect: function(url) { connectAsDefault(url); Central.login(); Meteor.subscribe("my_events"); States = new Meteor.Collection("States"); Events = new Meteor.Collection("Events"); }, /** * Logs the user into the Lens Central server. * * @param {Object} [opts] * @param {String} [opts.username] The user's username. Defaults to * "guest". * @param {String} [opts.password] The user's password. Defaults to * the empty string. * @param {Function} [callback] Function to call when the log in * is done. */ login: function(opts, callback) { check(opts, check.Match.Optional({ username: check.Match.Optional(String), password: check.Match.Optional(String) })); check(callback, check.Match.Optional(Function)); opts = opts || {}; Meteor.loginWithPassword(opts.username || "guest", opts.password || "guest", callback); Meteor.subscribe("this_user"); }, /** * Logs the user out of the Lens Central server. * * @param {Function} [callback] Function to call when the log out is * done. */ logout: function(callback) { check(callback, check.Match.Optional(Function)); Meteor.loginWithPassword("guest", "", callback); }, /** * Returns the current user record. A reactive data source. * @return {Object} The user record. */ user: Meteor.user, /** * Returns the current user ID. A reactive data source. * @return {String} The ID of the current user. */ userId: Meteor.userId, /** * Returns a {@link StateTracker}. Users can have multiple states at * the same time by creating multiple StateTrackers. * * @param {String} group Which group the states will belong to. * @memberOf Lens.Central */ StateTracker: function(group) { return StateTracker(group || DEFAULT_GROUP); }, /** * Logs an event to the Lens Central server. * @param {String} event Name of the event. * @param {Object} [opts] * @param {Any} [opts.data] Arbitrary data to associate with the * event. Must be JSON-serializable. * @param {String} [opts.group] Which group this event belongs to. */ logEvent: function(event, opts) { check(event, String); check(opts, check.Match.Optional({ data: check.Match.Optional(check.Match.Serializable), group: check.Match.Optional(String) })); if(!opts) { opts = {}; } Events.insert({ user: Meteor.userId(), name: event, data: opts.data, group: (opts.group || DEFAULT_GROUP), time: now() }); }, /** * Returns a database connected to the Central server. * @return {Lens.DB} */ db: function() { return DB("", null, function() { return Meteor.connection; }, false); }, /** * Returns the connection to the Lens Central server. See Meteor's * documentation on [DDP.connect](http://docs.meteor.com/#ddp_connect) * for documentation on connection options. */ connection: function() { return Meteor.connection; } }; Central.connect(Configuration["lens.central_url"]); Object.freeze(Central); Lens._addMember(Central, "Central"); return Central; });