/**
* 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;
});