Clean up observes created for connections that were closed before the

observe was set up.
This commit is contained in:
Emily Stark
2014-03-19 22:02:13 -07:00
parent 051faf8895
commit efd044a004

View File

@@ -558,9 +558,16 @@ Accounts._clearAllLoginTokens = function (userId) {
};
// connection id -> observe handle for the login token that this
// connection is currently associated with
// connection is currently associated with, or null. Null indicates that
// we are in the process of setting up the observe.
var userObservesForConnections = {};
// connection id -> boolean. Keeps track of connections that were closed
// before we had a chance to set up the observe on the user associated
// with this connection. To avoid leaking observes, we'll look in here
// immediately after setting up an observe.
var connectionsClosedBeforeObserve = {};
// test hook
Accounts._getUserObserve = function (connectionId) {
return userObservesForConnections[connectionId];
@@ -571,9 +578,17 @@ Accounts._getUserObserve = function (connectionId) {
// this token.
var removeTokenFromConnection = function (connectionId) {
var observe = userObservesForConnections[connectionId];
if (observe) {
delete userObservesForConnections[connectionId];
observe.stop();
if (observe !== undefined) {
if (observe === null) {
// We're in the process of setting up an observe for this
// connection. We can't clean up that observe yet, but we can make
// note of it in `connectionsClosedBeforeObserve`, so that the
// observe will get torn down immediately after being set up.
connectionsClosedBeforeObserve[connectionId] = true;
} else {
delete userObservesForConnections[connectionId];
observe.stop();
}
}
};
@@ -588,10 +603,15 @@ Accounts._setLoginToken = function (userId, connection, newToken) {
if (newToken) {
// Set up an observe for this token. If the token goes away, we need
// to close the connection. We defer this observe because there's
// to close the connection. We defer the observe because there's
// no need for it to be on the critical path for login; we just need
// to ensure that the connection will get closed at some point if
// the token gets deleted.
//
// Initially, we set the observe for this connection to null; this
// signifies to other code (which might run while we yield) that we
// are in the process of setting up an observe for this connection.
userObservesForConnections[connection.id] = null;
Meteor.defer(function () {
var foundMatchingUser;
// Because we upgrade unhashed login tokens to hashed tokens at
@@ -611,6 +631,12 @@ Accounts._setLoginToken = function (userId, connection, newToken) {
// lying around.
}
});
if (connectionsClosedBeforeObserve[connection.id]) {
// Oops, this connection was closed while we were setting up the
// observe. Clean it up now.
delete connectionsClosedBeforeObserve[connection.id];
removeTokenFromConnection(connection.id);
}
if (! foundMatchingUser) {
// We've set up an observe on the user associated with `newToken`,
// so if the new token is removed from the database, we'll close