From abd7f75ae97b74aa99d3adbb2748d06eb5e4ac5b Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Mon, 27 Feb 2006 21:56:39 +0000 Subject: [PATCH] Started work on invocation/receiver stuff, but jeez ActionScript is making it a pain in the ass. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3893 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/presents/client/Client.as | 4 +- .../presents/client/InvocationDecoder.as | 55 ++++++++ .../presents/client/InvocationDirector.as | 119 +++++++++++++++++- .../presents/client/InvocationReceiver.as | 51 ++++++++ .../presents/client/InvocationRegistration.as | 61 +++++++++ .../threerings/presents/data/ClientObject.as | 16 +++ 6 files changed, 299 insertions(+), 7 deletions(-) create mode 100644 src/as/com/threerings/presents/client/InvocationDecoder.as create mode 100644 src/as/com/threerings/presents/client/InvocationReceiver.as create mode 100644 src/as/com/threerings/presents/client/InvocationRegistration.as diff --git a/src/as/com/threerings/presents/client/Client.as b/src/as/com/threerings/presents/client/Client.as index 3d678c779..4b5540022 100644 --- a/src/as/com/threerings/presents/client/Client.as +++ b/src/as/com/threerings/presents/client/Client.as @@ -205,13 +205,13 @@ public class Client extends EventDispatcher } } - protected function gotClientObject (clobj :ClientObject) :void + internal function gotClientObject (clobj :ClientObject) :void { _clobj = clobj; notifyObservers(ClientEvent.CLIENT_DID_LOGON); } - protected function getClientObjectFailed (cause :Error) :void + internal function getClientObjectFailed (cause :Error) :void { notifyObservers(ClientEvent.CLIENT_FAILED_TO_LOGON, cause); } diff --git a/src/as/com/threerings/presents/client/InvocationDecoder.as b/src/as/com/threerings/presents/client/InvocationDecoder.as new file mode 100644 index 000000000..d30dc62d6 --- /dev/null +++ b/src/as/com/threerings/presents/client/InvocationDecoder.as @@ -0,0 +1,55 @@ +// +// $Id: InvocationDecoder.java 3099 2004-08-27 02:21:06Z mdb $ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.presents.client { + +import com.threerings.presents.Log; + +/** + * Provides the basic functionality used to dispatch invocation + * notification events. + */ +public /* abstract */ class InvocationDecoder +{ + /** The receiver for which we're decoding and dipatching + * notifications. */ + public var receiver :InvocationReceiver; + + /** + * Returns the generated hash code that is used to identify this + * invocation notification service. + */ + public /* abstract */ function getReceiverCode () :String + { + return "abstract"; + } + + /** + * Dispatches the specified method to our receiver. + */ + public function dispatchNotification (methodId :int, args :Array) :void + { + Log.warning("Requested to dispatch unknown method " + + "[receiver=" + receiver + ", methodId=" + methodId + + ", args=" + args + "]."); + } +} +} diff --git a/src/as/com/threerings/presents/client/InvocationDirector.as b/src/as/com/threerings/presents/client/InvocationDirector.as index 684b62a14..228b6cdd6 100644 --- a/src/as/com/threerings/presents/client/InvocationDirector.as +++ b/src/as/com/threerings/presents/client/InvocationDirector.as @@ -1,14 +1,22 @@ package com.threerings.presents.client { +import com.threerings.presents.dobj.DEvent; +import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DObjectManager; +import com.threerings.presents.dobj.DSet; +import com.threerings.presents.dobj.EventListener; +import com.threerings.presents.dobj.ObjectAccessError; +import com.threerings.presents.dobj.Subscriber; import com.threerings.presents.data.ClientObject; import com.threerings.presents.Log; public class InvocationDirector + implements EventListener { - public function init (omgr :DObjectManager, cloid :int, client :Client) :void + public function init (omgr :DObjectManager, cloid :int, client :Client) + :void { if (_clobj != null) { Log.warning("Zoiks, client object around during invmgr init!"); @@ -18,7 +26,7 @@ public class InvocationDirector _omgr = omgr; _client = client; - // TODO : lots more + _omgr.subscribeToObject(cloid, new ClientSubscriber(this)); } public function cleanup () :void @@ -28,10 +36,111 @@ public class InvocationDirector // TODO: lots more } - protected var _omgr :DObjectManager; + /** + * Registers an invocation notification receiver by way of its + * notification event decoder. + */ + public function registerReceiver (decoder :InvocationDecoder) :void + { + _reclist.push(decoder); - protected var _client :Client; + // if we're already online, assign a recevier id now + if (_clobj != null) { + assignReceiverId(decoder); + } + } - protected var _clobj :ClientObject; + // documentation inherited from interface EventListener + public function eventReceived (event :DEvent) :void + { + // TODO + } + + /** + * Assigns a receiver id to this decoder and publishes it in the + * {@link ClientObject#receivers} field. + */ + internal function assignReceiverId (decoder :InvocationDecoder) :void + { + // TODO + } + + /** + * Called when we log on; generates mappings for all receivers + * registered prior to logon. + */ + internal function assignReceiverIds () :void + { + _clobj.startTransaction(); + try { + for each (var decoder :InvocationDecoder in _reclist) { + assignReceiverId(decoder); + } + } finally { + _clobj.commitTransaction(); + } + } + + /** + * Called by the ClientSubscriber helper class when the client object + * has been returned by the server. + */ + public function gotClientObject (clobj :ClientObject) :void + { + clobj.addListener(this); + clobj.setReceivers(new DSet()); + _clobj = clobj; + assignReceiverIds(); + + _client.gotClientObject(clobj); + } + + /** + * Called by the ClientSubscriber helper class when it fails. + */ + public function gotClientObjectFailed (oid :int, cause :ObjectAccessError) + :void + { + Log.warning("Invocation director unable to subscribe to " + + "client object [cloid=" + oid + ", cause=" + cause + "]!"); + _client.getClientObjectFailed(cause); + } + + internal var _omgr :DObjectManager; + + internal var _client :Client; + + internal var _clobj :ClientObject; + + /** All registered receivers are maintained in a list so that we can + * assign receiver ids to them when we go online. */ + internal var _reclist :Array = new Array(); } } + +import com.threerings.presents.client.InvocationDirector; +import com.threerings.presents.data.ClientObject; +import com.threerings.presents.dobj.DObject; +import com.threerings.presents.dobj.ObjectAccessError; +import com.threerings.presents.dobj.Subscriber; +import com.threerings.presents.Log; + +class ClientSubscriber implements Subscriber +{ + public function ClientSubscriber (invdir :InvocationDirector) + { + _invdir = invdir; + } + + public function objectAvailable (obj :DObject) :void + { + _invdir.gotClientObject(obj as ClientObject); + } + + public function requestFailed (oid :int, cause :ObjectAccessError) :void + { + _invdir.gotClientObjectFailed(oid, cause); + } + + protected var _invdir :InvocationDirector; +} diff --git a/src/as/com/threerings/presents/client/InvocationReceiver.as b/src/as/com/threerings/presents/client/InvocationReceiver.as new file mode 100644 index 000000000..7e8fc1cb5 --- /dev/null +++ b/src/as/com/threerings/presents/client/InvocationReceiver.as @@ -0,0 +1,51 @@ +// +// $Id: InvocationReceiver.java 3099 2004-08-27 02:21:06Z mdb $ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.presents.client { + +import com.threerings.presents.dobj.DSet; + +/** + * Invocation notification receipt interfaces should be defined as + * extending this interface. Actual notification receivers will implement + * the requisite receiver interface definition and register themselves + * with the {@link InvocationDirector} using the generated {@link + * InvocationDecoder} class specific to the notification receiver + * interface in question. For example: + * + *
+ * public class FooDirector implements FooReceiver
+ * {
+ *     public FooDirector (PresentsContext ctx)
+ *     {
+ *         InvocationDirector idir = ctx.getClient().getInvocationDirector();
+ *         idir.registerReceiver(new FooDecoder(this));
+ *     }
+ * }
+ * 
+ * + * @see InvocationDirector#registerReceiver + */ +public interface InvocationReceiver +{ + // nada, but see InvocationRegistration +} +} diff --git a/src/as/com/threerings/presents/client/InvocationRegistration.as b/src/as/com/threerings/presents/client/InvocationRegistration.as new file mode 100644 index 000000000..39cdb6c9a --- /dev/null +++ b/src/as/com/threerings/presents/client/InvocationRegistration.as @@ -0,0 +1,61 @@ +package com.threerings.presents.client { + +import com.threerings.util.Comparable; + +import com.threerings.io.ObjectInputStream; +import com.threerings.io.ObjectOutputStream; + +import com.threerings.presents.dobj.DSet; +import com.threerings.presents.dobj.DSetEntry; + +/** + * Used to maintain a registry of invocation receivers that can be + * used to convert (large) hash codes into (small) registration + * numbers. + */ +public class InvocationRegistration + implements DSetEntry +{ + /** The unique hash code associated with this invocation receiver class. */ + public var receiverCode :String; + + /** The unique id assigned to this invocation receiver class at + * registration time. */ + public var receiverId :int; + + /** Creates and initializes a registration instance. */ + public function Registration (receiverCode :String, receiverId :int) + { + this.receiverCode = receiverCode; + this.receiverId = receiverId; + } + + // documentation inherited from interface DSetEntry + public function getKey () :Comparable + { + return null; // TODO receiverCode; + // TODO: maybe we drop the concept of Comparable and just + // use any old objects: screw performance + } + + // documentation inherited + public function toString () :String + { + return "[" + receiverCode + " => " + receiverId + "]"; + } + + // documentation inherited from superinterface Streamable + public function writeObject (out :ObjectOutputStream) :void + { + out.writeField(receiverCode); + out.writeShort(receiverId); + } + + // documentation inherited from superinterface Streamable + public function readObject (ins :ObjectInputStream) :void + { + receiverCode = (ins.readField(String) as String); + receiverId = ins.readShort(); + } +} +} diff --git a/src/as/com/threerings/presents/data/ClientObject.as b/src/as/com/threerings/presents/data/ClientObject.as index b633bde30..fe33415dd 100644 --- a/src/as/com/threerings/presents/data/ClientObject.as +++ b/src/as/com/threerings/presents/data/ClientObject.as @@ -21,6 +21,8 @@ package com.threerings.presents.data { +import mx.utils.ObjectUtil; + import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DSet; @@ -35,6 +37,11 @@ import com.threerings.io.ObjectOutputStream; */ public class ClientObject extends DObject { + // AUTO-GENERATED: FIELDS START + /** The field name of the receivers field. */ + public static const RECEIVERS :String = "receivers"; + // AUTO-GENERATED: FIELDS END + /** Used to publish all invocation service receivers registered on * this client. */ public var receivers :DSet; @@ -58,5 +65,14 @@ public class ClientObject extends DObject super.readObject(ins); receivers = (ins.readObject() as DSet); } + + // AUTO-GENERATED: METHODS START + public function setReceivers (value :DSet) :void + { + requestAttributeChange(RECEIVERS, value, this.receivers); + this.receivers = (value == null) ? null + : (ObjectUtil.copy(value) as DSet); + } + // AUTO-GENERATED: METHODS END } }