From b2b8f57454feaa6a5cbab4a51b2043b79870fde0 Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Thu, 15 Jan 2009 23:19:02 +0000 Subject: [PATCH] - Monitor logins to other nodes, boot any local sessions with the same authentication name. - Use new (ca. 2002) pattern of creating an overridable listener, rather than making the whole class a listener. Mdb told me to add this at the msoy level, but I think it belongs here. Presents simply expects a user to be in one place. It also occurs to me that we probably want something more sophisticated: there may be unpersisted data connected to the session that should be flushed prior to the session starting on another node. We may want something like a lock when users log-in, so that other nodes can terminate the session and flush any persistent data FIRST. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5635 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../presents/peer/server/PeerManager.java | 13 ++ .../presents/peer/server/PeerNode.java | 136 ++++++++++++------ 2 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/java/com/threerings/presents/peer/server/PeerManager.java b/src/java/com/threerings/presents/peer/server/PeerManager.java index d5ac8b92a..d94223ef2 100644 --- a/src/java/com/threerings/presents/peer/server/PeerManager.java +++ b/src/java/com/threerings/presents/peer/server/PeerManager.java @@ -984,6 +984,19 @@ public abstract class PeerManager return new PeerCreds(_nodeName, _sharedSecret); } + /** + * Called when we hear about a client logging on to another node. + */ + protected void clientLoggedOnOtherNode (String nodeName, ClientInfo clinfo) + { + PresentsSession session = _clmgr.getClient(clinfo.username); + if (session != null) { + log.info("Booting user that has connected on another node", + "username", clinfo.username, "otherNode", nodeName); + session.endSession(); + } + } + /** * Called when a peer connects to this server. */ diff --git a/src/java/com/threerings/presents/peer/server/PeerNode.java b/src/java/com/threerings/presents/peer/server/PeerNode.java index b65598c43..9a8e375f4 100644 --- a/src/java/com/threerings/presents/peer/server/PeerNode.java +++ b/src/java/com/threerings/presents/peer/server/PeerNode.java @@ -35,8 +35,14 @@ import com.threerings.presents.dobj.AttributeChangeListener; import com.threerings.presents.dobj.AttributeChangedEvent; import com.threerings.presents.dobj.DEvent; import com.threerings.presents.dobj.DObject; +import com.threerings.presents.dobj.DSet; +import com.threerings.presents.dobj.EntryAddedEvent; +import com.threerings.presents.dobj.EntryRemovedEvent; +import com.threerings.presents.dobj.EntryUpdatedEvent; import com.threerings.presents.dobj.ObjectAccessException; +import com.threerings.presents.dobj.SetListener; import com.threerings.presents.dobj.Subscriber; +import com.threerings.presents.peer.data.ClientInfo; import com.threerings.presents.peer.data.NodeObject; import com.threerings.presents.peer.net.PeerBootstrapData; import com.threerings.presents.peer.server.persist.NodeRecord; @@ -49,7 +55,7 @@ import static com.threerings.presents.Log.log; * Contains all runtime information for one of our peer nodes. */ public class PeerNode - implements ClientObserver, Subscriber, AttributeChangeListener + implements ClientObserver, Subscriber { /** This peer's node object. */ public NodeObject nodeobj; @@ -190,6 +196,8 @@ public class PeerNode public void clientDidLogoff (Client client) { _peermgr.disconnectedFromPeer(this); + nodeobj.removeListener(_listener); + _listener = null; nodeobj = null; } @@ -204,7 +212,7 @@ public class PeerNode { // listen for lock and cache updates nodeobj = object; - nodeobj.addListener(this); + nodeobj.addListener(_listener = createListener()); _peermgr.connectedToPeer(this); } @@ -216,49 +224,6 @@ public class PeerNode "[peer=" + _record + ", cause=" + cause + "]."); } - // documentation inherited from interface AttributeChangeListener - public void attributeChanged (AttributeChangedEvent event) - { - String name = event.getName(); - if (name.equals(NodeObject.ACQUIRING_LOCK)) { - NodeObject.Lock lock = nodeobj.acquiringLock; - PeerManager.LockHandler handler = _peermgr.getLockHandler(lock); - if (handler == null) { - if (_peermgr.getNodeObject().locks.contains(lock)) { - log.warning("Peer trying to acquire lock owned by this node " + - "[lock=" + lock + ", node=" + _record.nodeName + "]."); - return; - } - _peermgr.createLockHandler(this, lock, true); - return; - } - - // if the other node has priority, we're done - if (hasPriority(handler.getNodeName(), _record.nodeName)) { - return; - } - - // this node has priority, so cancel the existing handler and take over its listeners - ResultListenerList olisteners = handler.listeners; - handler.cancel(); - handler = _peermgr.createLockHandler(this, lock, true); - handler.listeners = olisteners; - - } else if (name.equals(NodeObject.RELEASING_LOCK)) { - NodeObject.Lock lock = nodeobj.releasingLock; - PeerManager.LockHandler handler = _peermgr.getLockHandler(lock); - if (handler == null) { - _peermgr.createLockHandler(this, lock, false); - } else { - log.warning("Received request to release resolving lock [node=" + - _record.nodeName + ", handler=" + handler + "]."); - } - - } else if (name.equals(NodeObject.CACHE_DATA)) { - _peermgr.changedCacheData(nodeobj.cacheData.cache, nodeobj.cacheData.data); - } - } - /** * Determines whether the first node named has priority over the second when resolving * lock disputes. @@ -275,10 +240,91 @@ public class PeerNode return new BlockingCommunicator(client); } + /** + * Create the NodeObjectListener to use. Overrideable. + */ + protected NodeObjectListener createListener () + { + return new NodeObjectListener(); + } + + /** + * Listens to node object changes. + */ + protected class NodeObjectListener + implements AttributeChangeListener, SetListener + { + // documentation inherited from interface AttributeChangeListener + public void attributeChanged (AttributeChangedEvent event) + { + String name = event.getName(); + if (name.equals(NodeObject.ACQUIRING_LOCK)) { + NodeObject.Lock lock = nodeobj.acquiringLock; + PeerManager.LockHandler handler = _peermgr.getLockHandler(lock); + if (handler == null) { + if (_peermgr.getNodeObject().locks.contains(lock)) { + log.warning("Peer trying to acquire lock owned by this node " + + "[lock=" + lock + ", node=" + _record.nodeName + "]."); + return; + } + _peermgr.createLockHandler(PeerNode.this, lock, true); + return; + } + + // if the other node has priority, we're done + if (hasPriority(handler.getNodeName(), _record.nodeName)) { + return; + } + + // this node has priority, so cancel the existing handler and take over + // its listeners + ResultListenerList olisteners = handler.listeners; + handler.cancel(); + handler = _peermgr.createLockHandler(PeerNode.this, lock, true); + handler.listeners = olisteners; + + } else if (name.equals(NodeObject.RELEASING_LOCK)) { + NodeObject.Lock lock = nodeobj.releasingLock; + PeerManager.LockHandler handler = _peermgr.getLockHandler(lock); + if (handler == null) { + _peermgr.createLockHandler(PeerNode.this, lock, false); + } else { + log.warning("Received request to release resolving lock", + "node", _record.nodeName, "handler", handler); + } + + } else if (name.equals(NodeObject.CACHE_DATA)) { + _peermgr.changedCacheData(nodeobj.cacheData.cache, nodeobj.cacheData.data); + } + } + + // documentation inherited from interface SetListener + public void entryAdded (EntryAddedEvent event) + { + String name = event.getName(); + if (NodeObject.CLIENTS.equals(name)) { + _peermgr.clientLoggedOnOtherNode(getNodeName(), (ClientInfo)event.getEntry()); + } + } + + // documentation inherited from interface SetListener + public void entryUpdated (EntryUpdatedEvent event) + { + // nada + } + + // documentation inherited from interface SetListener + public void entryRemoved (EntryRemovedEvent event) + { + // nada + } + } // END: class NodeObjectListener + protected PeerManager _peermgr; protected PresentsDObjectMgr _omgr; protected ConnectionManager _conmgr; protected NodeRecord _record; + protected NodeObjectListener _listener; protected Client _client; protected long _lastConnectStamp;