Make the zone handling appropriately peer-aware. It's worth noting that due to adding moveRequiresServerSwitch() to ZoneService, this will break some things which use this.

git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@913 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Mike Thomas
2010-05-27 20:30:53 +00:00
parent c01ff63cd6
commit adeb3054d4
11 changed files with 519 additions and 14 deletions
@@ -7,6 +7,7 @@ import com.threerings.util.ResultListener;
import com.threerings.presents.client.BasicDirector; import com.threerings.presents.client.BasicDirector;
import com.threerings.presents.client.Client; import com.threerings.presents.client.Client;
import com.threerings.presents.client.ClientEvent; import com.threerings.presents.client.ClientEvent;
import com.threerings.presents.client.ConfirmAdapter;
import com.threerings.crowd.data.PlaceConfig; import com.threerings.crowd.data.PlaceConfig;
@@ -97,22 +98,31 @@ public class ZoneDirector extends BasicDirector
return false; return false;
} }
_pendingZoneId = zoneId;
sendMoveRequest();
return true;
}
protected function sendMoveRequest () :void
{
// let our zone observers know that we're attempting to switch zones // let our zone observers know that we're attempting to switch zones
notifyObservers(zoneId); notifyObservers(_pendingZoneId);
// check the version of our cached copy of the scene to which we're requesting to move; if // check the version of our cached copy of the scene to which we're requesting to move; if
// we were unable to load it, assume a cached version of zero // we were unable to load it, assume a cached version of zero
var sceneVers :int = 0; var sceneVers :int = 0;
var sceneId :int = -1;
var pendingModel :SceneModel = _scdir.getPendingModel(); var pendingModel :SceneModel = _scdir.getPendingModel();
if (pendingModel != null) { if (pendingModel != null) {
sceneVers = pendingModel.version; sceneVers = pendingModel.version;
} }
// issue a moveTo request // issue a moveTo request
log.info("Issuing zoned moveTo(" + ZoneUtil.toString(zoneId) + log.info("Issuing zoned moveTo(" + ZoneUtil.toString(_pendingZoneId) +
", " + sceneId + ", " + sceneVers + ")."); ", " + sceneId + ", " + sceneVers + ").");
_zservice.moveTo(zoneId, sceneId, sceneVers, this); _zservice.moveTo(_pendingZoneId, sceneId, sceneVers, this);
return true;
} }
override protected function fetchServices (client :Client) :void override protected function fetchServices (client :Client) :void
@@ -141,6 +151,9 @@ public class ZoneDirector extends BasicDirector
// keep track of the summary // keep track of the summary
_summary = summary; _summary = summary;
// We're not heading there any more.
_pendingZoneId = -1;
// pass the rest off to the standard scene transition code // pass the rest off to the standard scene transition code
_scdir.moveSucceeded(placeId, config); _scdir.moveSucceeded(placeId, config);
@@ -156,6 +169,9 @@ public class ZoneDirector extends BasicDirector
// keep track of the summary // keep track of the summary
_summary = summary; _summary = summary;
// We're not heading there any more.
_pendingZoneId = -1;
// pass the rest off to the standard scene transition code // pass the rest off to the standard scene transition code
_scdir.moveSucceededWithUpdates(placeId, config, updates); _scdir.moveSucceededWithUpdates(placeId, config, updates);
@@ -170,6 +186,9 @@ public class ZoneDirector extends BasicDirector
// keep track of the summary // keep track of the summary
_summary = summary; _summary = summary;
// We're not heading there any more.
_pendingZoneId = -1;
// pass the rest off to the standard scene transition code // pass the rest off to the standard scene transition code
_scdir.moveSucceededWithScene(placeId, config, model); _scdir.moveSucceededWithScene(placeId, config, model);
@@ -177,6 +196,17 @@ public class ZoneDirector extends BasicDirector
notifyObservers(summary); notifyObservers(summary);
} }
// from interface ZoneService_ZoneMoveListener
public function moveRequiresServerSwitch (hostname :String, ports :TypedArray) :void
{
log.info("Zone switch requires server switch", "host", hostname, "ports", ports);
// ship on over to the other server
_wCtx.getClient().moveToServer(hostname, ports, new ConfirmAdapter(
function () :void { // succeeded
sendMoveRequest();
}, requestFailed));
}
// from interface ZoneService.ZoneMoveListener // from interface ZoneService.ZoneMoveListener
public function requestFailed (reason :String) :void public function requestFailed (reason :String) :void
{ {
@@ -215,6 +245,9 @@ public class ZoneDirector extends BasicDirector
return; // if we're currently somewhere, just stay there return; // if we're currently somewhere, just stay there
} }
// Not gonna get there, so clear it.
_pendingZoneId = -1;
// otherwise if we were previously in a zone/scene, try going back there // otherwise if we were previously in a zone/scene, try going back there
if (_previousZoneId != -1) { if (_previousZoneId != -1) {
moveTo(_previousZoneId, previousSceneId); moveTo(_previousZoneId, previousSceneId);
@@ -263,5 +296,8 @@ public class ZoneDirector extends BasicDirector
/** Our previous zone id. */ /** Our previous zone id. */
protected var _previousZoneId :int = -1; protected var _previousZoneId :int = -1;
/** Where we're headed. */
protected var _pendingZoneId :int = -1;
} }
} }
@@ -33,6 +33,9 @@ import com.threerings.whirled.zone.data.ZoneSummary;
public interface ZoneService_ZoneMoveListener public interface ZoneService_ZoneMoveListener
extends InvocationService_InvocationListener extends InvocationService_InvocationListener
{ {
// from Java ZoneService_ZoneMoveListener
function moveRequiresServerSwitch (arg1 :String, arg2 :TypedArray /* of int */) :void
// from Java ZoneService_ZoneMoveListener // from Java ZoneService_ZoneMoveListener
function moveSucceeded (arg1 :int, arg2 :PlaceConfig, arg3 :ZoneSummary) :void function moveSucceeded (arg1 :int, arg2 :PlaceConfig, arg3 :ZoneSummary) :void
@@ -33,19 +33,27 @@ import com.threerings.whirled.zone.client.ZoneService_ZoneMoveListener;
public class ZoneMarshaller_ZoneMoveMarshaller public class ZoneMarshaller_ZoneMoveMarshaller
extends InvocationMarshaller_ListenerMarshaller extends InvocationMarshaller_ListenerMarshaller
{ {
/** The method id used to dispatch <code>moveRequiresServerSwitch</code> responses. */
public static const MOVE_REQUIRES_SERVER_SWITCH :int = 1;
/** The method id used to dispatch <code>moveSucceeded</code> responses. */ /** The method id used to dispatch <code>moveSucceeded</code> responses. */
public static const MOVE_SUCCEEDED :int = 1; public static const MOVE_SUCCEEDED :int = 2;
/** The method id used to dispatch <code>moveSucceededWithScene</code> responses. */ /** The method id used to dispatch <code>moveSucceededWithScene</code> responses. */
public static const MOVE_SUCCEEDED_WITH_SCENE :int = 2; public static const MOVE_SUCCEEDED_WITH_SCENE :int = 3;
/** The method id used to dispatch <code>moveSucceededWithUpdates</code> responses. */ /** The method id used to dispatch <code>moveSucceededWithUpdates</code> responses. */
public static const MOVE_SUCCEEDED_WITH_UPDATES :int = 3; public static const MOVE_SUCCEEDED_WITH_UPDATES :int = 4;
// from InvocationMarshaller_ListenerMarshaller // from InvocationMarshaller_ListenerMarshaller
override public function dispatchResponse (methodId :int, args :Array) :void override public function dispatchResponse (methodId :int, args :Array) :void
{ {
switch (methodId) { switch (methodId) {
case MOVE_REQUIRES_SERVER_SWITCH:
(listener as ZoneService_ZoneMoveListener).moveRequiresServerSwitch(
(args[0] as String), (args[1] as TypedArray /* of int */));
return;
case MOVE_SUCCEEDED: case MOVE_SUCCEEDED:
(listener as ZoneService_ZoneMoveListener).moveSucceeded( (listener as ZoneService_ZoneMoveListener).moveSucceeded(
(args[0] as int), (args[1] as PlaceConfig), (args[2] as ZoneSummary)); (args[0] as int), (args[1] as PlaceConfig), (args[2] as ZoneSummary));
@@ -129,22 +129,31 @@ public class ZoneDirector extends BasicDirector
return false; return false;
} }
_pendingZoneId = zoneId;
sendMoveRequest();
return true;
}
protected void sendMoveRequest ()
{
// let our zone observers know that we're attempting to switch zones // let our zone observers know that we're attempting to switch zones
notifyObservers(Integer.valueOf(zoneId)); notifyObservers(Integer.valueOf(_pendingZoneId));
// check the version of our cached copy of the scene to which we're requesting to move; if // check the version of our cached copy of the scene to which we're requesting to move; if
// we were unable to load it, assume a cached version of zero // we were unable to load it, assume a cached version of zero
int sceneVers = 0; int sceneVers = 0;
int sceneId = -1;
SceneModel pendingModel = _scdir.getPendingModel(); SceneModel pendingModel = _scdir.getPendingModel();
if (pendingModel != null) { if (pendingModel != null) {
sceneVers = pendingModel.version; sceneVers = pendingModel.version;
sceneId = pendingModel.sceneId;
} }
// issue a moveTo request // issue a moveTo request
log.info("Issuing zoned moveTo(" + ZoneUtil.toString(zoneId) + log.info("Issuing zoned moveTo(" + ZoneUtil.toString(_pendingZoneId) +
", " + sceneId + ", " + sceneVers + ")."); ", " + sceneId + ", " + sceneVers + ").");
_zservice.moveTo(_ctx.getClient(), zoneId, sceneId, sceneVers, this); _zservice.moveTo(_ctx.getClient(), _pendingZoneId, + sceneId, sceneVers, this);
return true;
} }
@Override @Override
@@ -164,6 +173,21 @@ public class ZoneDirector extends BasicDirector
_previousZoneId = -1; _previousZoneId = -1;
} }
// from interface SceneService.SceneMoveListener
public void moveRequiresServerSwitch (String hostname, int[] ports)
{
// ship on over to the other server
_ctx.getClient().moveToServer(hostname, ports, new ZoneService.ConfirmListener() {
public void requestProcessed () {
// resend our move request now that we're connected to the new server
sendMoveRequest();
}
public void requestFailed (String reason) {
ZoneDirector.this.requestFailed(reason);
}
});
}
// from interface ZoneService.ZoneMoveListener // from interface ZoneService.ZoneMoveListener
public void moveSucceeded (int placeId, PlaceConfig config, ZoneSummary summary) public void moveSucceeded (int placeId, PlaceConfig config, ZoneSummary summary)
{ {
@@ -175,6 +199,9 @@ public class ZoneDirector extends BasicDirector
// keep track of the summary // keep track of the summary
_summary = summary; _summary = summary;
// We're not heading there any more.
_pendingZoneId = -1;
// pass the rest off to the standard scene transition code // pass the rest off to the standard scene transition code
_scdir.moveSucceeded(placeId, config); _scdir.moveSucceeded(placeId, config);
@@ -189,6 +216,9 @@ public class ZoneDirector extends BasicDirector
// keep track of the summary // keep track of the summary
_summary = summary; _summary = summary;
// We're not heading there any more.
_pendingZoneId = -1;
// pass the rest off to the standard scene transition code // pass the rest off to the standard scene transition code
_scdir.moveSucceededWithUpdates(placeId, config, updates); _scdir.moveSucceededWithUpdates(placeId, config, updates);
@@ -203,6 +233,9 @@ public class ZoneDirector extends BasicDirector
// keep track of the summary // keep track of the summary
_summary = summary; _summary = summary;
// We're not heading there any more.
_pendingZoneId = -1;
// pass the rest off to the standard scene transition code // pass the rest off to the standard scene transition code
_scdir.moveSucceededWithScene(placeId, config, model); _scdir.moveSucceededWithScene(placeId, config, model);
@@ -247,6 +280,9 @@ public class ZoneDirector extends BasicDirector
return; // if we're currently somewhere, just stay there return; // if we're currently somewhere, just stay there
} }
// Not gonna get there, so clear it.
_pendingZoneId = -1;
// otherwise if we were previously in a zone/scene, try going back there // otherwise if we were previously in a zone/scene, try going back there
if (_previousZoneId != -1) { if (_previousZoneId != -1) {
moveTo(_previousZoneId, previousSceneId); moveTo(_previousZoneId, previousSceneId);
@@ -295,4 +331,7 @@ public class ZoneDirector extends BasicDirector
/** Our previous zone id. */ /** Our previous zone id. */
protected int _previousZoneId = -1; protected int _previousZoneId = -1;
/** Where we're headed. */
protected int _pendingZoneId = -1;
} }
@@ -56,6 +56,12 @@ public interface ZoneService extends InvocationService
*/ */
public void moveSucceededWithScene ( public void moveSucceededWithScene (
int placeId, PlaceConfig config, ZoneSummary summary, SceneModel model); int placeId, PlaceConfig config, ZoneSummary summary, SceneModel model);
/**
* Indicates that the client must switch to the specified server and reissue its move
* request in order to relocate to its desired zone.
*/
public void moveRequiresServerSwitch (String hostname, int[] ports);
} }
/** /**
@@ -49,9 +49,22 @@ public class ZoneMarshaller extends InvocationMarshaller
public static class ZoneMoveMarshaller extends ListenerMarshaller public static class ZoneMoveMarshaller extends ListenerMarshaller
implements ZoneMoveListener implements ZoneMoveListener
{ {
/** The method id used to dispatch {@link #moveRequiresServerSwitch}
* responses. */
public static final int MOVE_REQUIRES_SERVER_SWITCH = 1;
// from interface ZoneMoveMarshaller
public void moveRequiresServerSwitch (String arg1, int[] arg2)
{
_invId = null;
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, MOVE_REQUIRES_SERVER_SWITCH,
new Object[] { arg1, arg2 }, transport));
}
/** The method id used to dispatch {@link #moveSucceeded} /** The method id used to dispatch {@link #moveSucceeded}
* responses. */ * responses. */
public static final int MOVE_SUCCEEDED = 1; public static final int MOVE_SUCCEEDED = 2;
// from interface ZoneMoveMarshaller // from interface ZoneMoveMarshaller
public void moveSucceeded (int arg1, PlaceConfig arg2, ZoneSummary arg3) public void moveSucceeded (int arg1, PlaceConfig arg2, ZoneSummary arg3)
@@ -64,7 +77,7 @@ public class ZoneMarshaller extends InvocationMarshaller
/** The method id used to dispatch {@link #moveSucceededWithScene} /** The method id used to dispatch {@link #moveSucceededWithScene}
* responses. */ * responses. */
public static final int MOVE_SUCCEEDED_WITH_SCENE = 2; public static final int MOVE_SUCCEEDED_WITH_SCENE = 3;
// from interface ZoneMoveMarshaller // from interface ZoneMoveMarshaller
public void moveSucceededWithScene (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneModel arg4) public void moveSucceededWithScene (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneModel arg4)
@@ -77,7 +90,7 @@ public class ZoneMarshaller extends InvocationMarshaller
/** The method id used to dispatch {@link #moveSucceededWithUpdates} /** The method id used to dispatch {@link #moveSucceededWithUpdates}
* responses. */ * responses. */
public static final int MOVE_SUCCEEDED_WITH_UPDATES = 3; public static final int MOVE_SUCCEEDED_WITH_UPDATES = 4;
// from interface ZoneMoveMarshaller // from interface ZoneMoveMarshaller
public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneUpdate[] arg4) public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneUpdate[] arg4)
@@ -92,6 +105,11 @@ public class ZoneMarshaller extends InvocationMarshaller
public void dispatchResponse (int methodId, Object[] args) public void dispatchResponse (int methodId, Object[] args)
{ {
switch (methodId) { switch (methodId) {
case MOVE_REQUIRES_SERVER_SWITCH:
((ZoneMoveListener)listener).moveRequiresServerSwitch(
(String)args[0], (int[])args[1]);
return;
case MOVE_SUCCEEDED: case MOVE_SUCCEEDED:
((ZoneMoveListener)listener).moveSucceeded( ((ZoneMoveListener)listener).moveSucceeded(
((Integer)args[0]).intValue(), (PlaceConfig)args[1], (ZoneSummary)args[2]); ((Integer)args[0]).intValue(), (PlaceConfig)args[1], (ZoneSummary)args[2]);
@@ -0,0 +1,38 @@
package com.threerings.whirled.zone.peer.data;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.util.Name;
import com.threerings.presents.dobj.DSet;
/**
* Represents a zone hosted on some node.
*/
public class HostedZone extends SimpleStreamableObject
implements DSet.Entry
{
/** The unique ID for the zone in question. */
public int zoneId;
/** The name of the zone being hosted. */
public Name name;
public HostedZone ()
{
}
public HostedZone (int zoneId, Name name)
{
this.zoneId = zoneId;
this.name = name;
}
// from DSet.Entry
public Comparable<?> getKey ()
{
return zoneId;
}
}
@@ -0,0 +1,11 @@
package com.threerings.whirled.zone.peer.server;
import com.threerings.whirled.zone.peer.server.PeeredZoneRegistry.PeerZoneShutdownListener;
import com.threerings.whirled.zone.server.ZoneManager;
public interface PeeredZoneManager
extends ZoneManager
{
/** Registers a shutdown listener with the zone. */
public void setShutdownListener (int zoneId, PeerZoneShutdownListener shutdowner);
}
@@ -0,0 +1,193 @@
package com.threerings.whirled.zone.peer.server;
import com.google.inject.Inject;
import com.samskivert.util.ResultListener;
import com.samskivert.util.Tuple;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.InvocationCodes;
import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.InvocationManager;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.server.LocationManager;
import com.threerings.whirled.server.SceneRegistry;
import com.threerings.whirled.zone.client.ZoneService;
import com.threerings.whirled.zone.data.ZoneCodes;
import com.threerings.whirled.zone.data.ZoneSummary;
import com.threerings.whirled.zone.peer.data.HostedZone;
import com.threerings.whirled.zone.server.ZoneManager;
import com.threerings.whirled.zone.server.ZoneMoveHandler;
import com.threerings.whirled.zone.server.ZoneRegistry;
import com.threerings.whirled.zone.server.ZoneManager.ResolutionListener;
import static com.threerings.whirled.zone.Log.log;
public abstract class PeeredZoneRegistry extends ZoneRegistry
{
/**
* Peer-awareness for finding out about zones.
*/
public static interface PeerZoneResolutionListener extends ResolutionListener
{
/**
* Called when the zone is already hosted on another node.
*/
public void zoneOnNode (Tuple<String, HostedZone> nodeInfo);
}
/**
* Peered zones should be sure to call back to one of these when they're going away.
*/
public static interface PeerZoneShutdownListener
{
public void zoneDidShutdown (int zoneId);
}
/**
* A ZoneMoveHandler that can receive the sceneOnNode() callback.
*/
public abstract static class PeerZoneMoveHandler extends ZoneMoveHandler
implements PeerZoneResolutionListener
{
public PeerZoneMoveHandler (
LocationManager locman, ZoneManager zmgr, SceneRegistry scReg, BodyObject body,
int sceneId, int sceneVer, ZoneService.ZoneMoveListener listener)
{
super(locman, zmgr, scReg, body, sceneId, sceneVer, listener);
}
}
protected abstract PeerZoneMoveHandler createMoveHandler (LocationManager locman,
ZoneManager zmgr, SceneRegistry scReg, BodyObject body, int sceneId, int sceneVer,
ZoneService.ZoneMoveListener listener);
@Inject public PeeredZoneRegistry (InvocationManager invmgr, ZonePeerManager peerMgr)
{
super(invmgr);
_peerMgr = peerMgr;
}
public void registerZoneManager (byte zoneType, ZoneManager manager)
{
if (!(manager instanceof PeeredZoneManager)) {
throw new IllegalArgumentException("All ZoneManagers received by PeeredZoneRegistry " +
"must be PeeredZoneManagers");
}
super.registerZoneManager(zoneType, manager);
}
@Override
public PeeredZoneManager getZoneManager (int qualifiedZoneId)
{
return (PeeredZoneManager)super.getZoneManager(qualifiedZoneId);
}
@Override
public void moveTo (ClientObject caller, int zoneId, int sceneId,
int sceneVer, ZoneService.ZoneMoveListener listener)
throws InvocationException
{
if (!(caller instanceof BodyObject)) {
log.warning("Request to switch zones by non-BodyObject " +
"[clobj=" + caller.getClass() + "].");
throw new InvocationException(ZoneCodes.INTERNAL_ERROR);
}
BodyObject body = (BodyObject)caller;
PeerZoneMoveHandler handler = createMoveHandler(_locman, getZoneManager(zoneId),
_screg, body, sceneId, sceneVer, listener);
resolvePeerZone(zoneId, handler);
}
public void resolveZone (int zoneId, ResolutionListener listener)
{
PeeredZoneManager zmgr = getZoneManager(zoneId);
if (zmgr == null) {
log.warning("Trying to resolve a zone for which we have no manager", "zoneId", zoneId);
listener.zoneFailedToResolve(zoneId, new Exception(InvocationCodes.INTERNAL_ERROR));
} else {
zmgr.resolveZone(zoneId, listener);
}
}
/**
* Resolve a zone, or return the information on the peer on which it's hosted.
*/
public void resolvePeerZone (final int zoneId, final PeerZoneResolutionListener listener)
{
// check to see if the destination zone is already hosted on a server
Tuple<String, HostedZone> nodeInfo = _peerMgr.getZoneHost(zoneId);
// if it's already hosted...
if (nodeInfo != null) {
// it's hosted on this server! It should already be resolved...
if (_peerMgr.getNodeObject().nodeName.equals(nodeInfo.left)) {
resolveZone(zoneId, listener);
} else {
listener.zoneOnNode(nodeInfo); // somewhere else, pass the buck
}
return;
}
// otherwise the zone is not resolved here nor there; so we claim the zone by acquiring a
// distributed lock and then resolve it locally
_peerMgr.acquireLock(ZonePeerManager.getZoneLock(zoneId), new ResultListener<String>() {
public void requestCompleted (String nodeName) {
if (_peerMgr.getNodeObject().nodeName.equals(nodeName)) {
log.debug("Got lock, resolving zone", "zoneId", zoneId);
resolveZone(zoneId, new ResolutionListener() {
public void zoneWasResolved (ZoneSummary zonesum) {
releaseLock();
_peerMgr.zoneDidStartup(zonesum.zoneId, zonesum.name);
PeerZoneShutdownListener shutdowner = new PeerZoneShutdownListener() {
public void zoneDidShutdown (int zoneId) {
_peerMgr.zoneDidShutdown(zoneId);
}
};
getZoneManager(zonesum.zoneId).setShutdownListener(
zonesum.zoneId, shutdowner);
listener.zoneWasResolved(zonesum);
}
public void zoneFailedToResolve (int zoneId, Exception reason) {
releaseLock();
listener.zoneFailedToResolve(zoneId, reason);
}
protected void releaseLock () {
_peerMgr.releaseLock(ZonePeerManager.getZoneLock(zoneId),
new ResultListener.NOOP<String>());
}
});
} else {
// we didn't get the lock, so let's see what happened by re-checking
Tuple<String, HostedZone> nodeInfo = _peerMgr.getZoneHost(zoneId);
if (nodeName == null || nodeInfo == null || !nodeName.equals(nodeInfo.left)) {
log.warning("Zone resolved on wacked-out node?",
"zoneId", zoneId, "nodeName", nodeName, "nodeInfo", nodeInfo);
listener.zoneFailedToResolve(zoneId,
new Exception("Zone on bogus host node"));
} else {
listener.zoneOnNode(nodeInfo); // somewhere else
}
}
}
public void requestFailed (Exception cause) {
log.warning("Failed to acquire zone resolution lock", "id", zoneId, cause);
listener.zoneFailedToResolve(zoneId, cause);
}
});
}
/**
* Pass on that the zone has shutdown.
*/
public void zoneDidShutdown (int zoneId)
{
_peerMgr.zoneDidShutdown(zoneId);
}
protected ZonePeerManager _peerMgr;
}
@@ -0,0 +1,73 @@
package com.threerings.whirled.zone.peer.server;
import javax.annotation.Generated;
import com.threerings.presents.dobj.DSet;
import com.threerings.crowd.peer.data.CrowdNodeObject;
import com.threerings.whirled.zone.peer.data.HostedZone;
public class ZoneNodeObject extends CrowdNodeObject
{
// AUTO-GENERATED: FIELDS START
/** The field name of the <code>hostedZones</code> field. */
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public static final String HOSTED_ZONES = "hostedZones";
// AUTO-GENERATED: FIELDS END
/** Contains info on all zones hosted by this server. */
public DSet<HostedZone> hostedZones = DSet.newDSet();
// AUTO-GENERATED: METHODS START
/**
* Requests that the specified entry be added to the
* <code>hostedZones</code> set. The set will not change until the event is
* actually propagated through the system.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void addToHostedZones (HostedZone elem)
{
requestEntryAdd(HOSTED_ZONES, hostedZones, elem);
}
/**
* Requests that the entry matching the supplied key be removed from
* the <code>hostedZones</code> set. The set will not change until the
* event is actually propagated through the system.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void removeFromHostedZones (Comparable<?> key)
{
requestEntryRemove(HOSTED_ZONES, hostedZones, key);
}
/**
* Requests that the specified entry be updated in the
* <code>hostedZones</code> set. The set will not change until the event is
* actually propagated through the system.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void updateHostedZones (HostedZone elem)
{
requestEntryUpdate(HOSTED_ZONES, hostedZones, elem);
}
/**
* Requests that the <code>hostedZones</code> field be set to the
* specified value. Generally one only adds, updates and removes
* entries of a distributed set, but certain situations call for a
* complete replacement of the set value. The local value will be
* updated immediately and an event will be propagated through the
* system to notify all listeners that the attribute did
* change. Proxied copies of this object (on clients) will apply the
* value change when they received the attribute changed notification.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void setHostedZones (DSet<HostedZone> value)
{
requestAttributeChange(HOSTED_ZONES, value, this.hostedZones);
DSet<HostedZone> clone = (value == null) ? null : value.clone();
this.hostedZones = clone;
}
// AUTO-GENERATED: METHODS END
}
@@ -0,0 +1,80 @@
package com.threerings.whirled.zone.peer.server;
import com.google.common.base.Function;
import com.google.inject.Inject;
import com.samskivert.util.Lifecycle;
import com.samskivert.util.Tuple;
import com.threerings.util.Name;
import com.threerings.presents.peer.data.NodeObject;
import com.threerings.crowd.peer.server.CrowdPeerManager;
import com.threerings.whirled.zone.peer.data.HostedZone;
import static com.threerings.whirled.zone.Log.log;
public abstract class ZonePeerManager extends CrowdPeerManager
{
/**
* Creates an uninitialized peer manager.
*/
@Inject public ZonePeerManager (Lifecycle cycle)
{
super(cycle);
}
@Override // from CrowdPeerManager
protected NodeObject createNodeObject ()
{
return new ZoneNodeObject();
}
/** Returns a lock used to claim resolution of the specified scene. */
public static NodeObject.Lock getZoneLock (int sceneId)
{
return new NodeObject.Lock("ZoneHost", sceneId);
}
/**
* Returns the node name of the peer that is hosting the specified scene, or null if no peer
* has published that they are hosting the scene.
*/
public Tuple<String, HostedZone> getZoneHost (final int zoneId)
{
return lookupNodeDatum(new NodeFunc<Tuple<String, HostedZone>>() {
public Tuple<String, HostedZone> apply (ZoneNodeObject nodeobj) {
HostedZone info = nodeobj.hostedZones.get(zoneId);
return (info == null) ? null : Tuple.newTuple(nodeobj.nodeName, info);
}
});
}
/**
* Called by the ZoneManager when it is hosting a zone.
*/
public void zoneDidStartup (int zoneId, Name name)
{
log.debug("Hosting zone", "id", zoneId, "name", name);
((ZoneNodeObject)_nodeobj).addToHostedZones(new HostedZone(zoneId, name));
}
/**
* Called by the ZoneManager when it is no longer hosting a scene.
*/
public void zoneDidShutdown (int zoneId)
{
log.debug("No longer hosting zone", "id", zoneId);
((ZoneNodeObject)_nodeobj).removeFromHostedZones(zoneId);
}
/** Useful with {@link #lookupNodeDatum}. */
public static abstract class NodeFunc<T> implements Function<NodeObject, T>
{
public abstract T apply (ZoneNodeObject mnobj);
public T apply (NodeObject nodeobj) {
return apply((ZoneNodeObject)nodeobj);
}
}
}