The great invocation services rethink of 2002! Rearchitected the remote
method invocation services and converted everything to the new style. Could this be my biggest checkin ever? git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1642 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// $Id: ChatDecoder.java,v 1.1 2002/08/14 19:07:49 mdb Exp $
|
||||
|
||||
package com.threerings.crowd.chat;
|
||||
|
||||
import com.threerings.crowd.chat.ChatReceiver;
|
||||
import com.threerings.presents.client.InvocationDecoder;
|
||||
|
||||
/**
|
||||
* Dispatches calls to a {@link ChatReceiver} instance.
|
||||
*/
|
||||
public class ChatDecoder extends InvocationDecoder
|
||||
{
|
||||
/** The generated hash code used to identify this receiver class. */
|
||||
public static final String RECEIVER_CODE = "50d26fa68e407846184dc06b78db3e1d";
|
||||
|
||||
/** The method id used to dispatch {@link ChatReceiver#receivedTell}
|
||||
* notifications. */
|
||||
public static final int RECEIVED_TELL = 1;
|
||||
|
||||
/**
|
||||
* Creates a decoder that may be registered to dispatch invocation
|
||||
* service notifications to the specified receiver.
|
||||
*/
|
||||
public ChatDecoder (ChatReceiver receiver)
|
||||
{
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public String getReceiverCode ()
|
||||
{
|
||||
return RECEIVER_CODE;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void dispatchNotification (int methodId, Object[] args)
|
||||
{
|
||||
switch (methodId) {
|
||||
case RECEIVED_TELL:
|
||||
((ChatReceiver)receiver).receivedTell(
|
||||
(String)args[0], (String)args[1], (String)args[2]
|
||||
);
|
||||
return;
|
||||
|
||||
default:
|
||||
super.dispatchNotification(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
// Generated on 11:25:46 08/12/02.
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: ChatDirector.java,v 1.32 2002/08/14 00:48:57 shaper Exp $
|
||||
// $Id: ChatDirector.java,v 1.33 2002/08/14 19:07:49 mdb Exp $
|
||||
|
||||
package com.threerings.crowd.chat;
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.samskivert.util.Tuple;
|
||||
|
||||
import com.threerings.presents.client.*;
|
||||
import com.threerings.presents.dobj.*;
|
||||
@@ -26,9 +25,8 @@ import com.threerings.crowd.util.CrowdContext;
|
||||
* services. It handles both place constrained chat as well as direct
|
||||
* messaging.
|
||||
*/
|
||||
public class ChatDirector
|
||||
implements LocationObserver, MessageListener, InvocationReceiver,
|
||||
ChatCodes
|
||||
public class ChatDirector extends BasicDirector
|
||||
implements ChatCodes, LocationObserver, MessageListener, ChatReceiver
|
||||
{
|
||||
/**
|
||||
* An interface that can receive information about the {@link
|
||||
@@ -50,6 +48,8 @@ public class ChatDirector
|
||||
*/
|
||||
public ChatDirector (CrowdContext ctx, MessageManager msgmgr, String bundle)
|
||||
{
|
||||
super(ctx);
|
||||
|
||||
// keep the context around
|
||||
_ctx = ctx;
|
||||
_msgmgr = msgmgr;
|
||||
@@ -57,7 +57,7 @@ public class ChatDirector
|
||||
|
||||
// register for chat notifications
|
||||
_ctx.getClient().getInvocationDirector().registerReceiver(
|
||||
MODULE_NAME, this);
|
||||
new ChatDecoder(this));
|
||||
|
||||
// register ourselves as a location observer
|
||||
_ctx.getLocationDirector().addLocationObserver(this);
|
||||
@@ -218,41 +218,55 @@ public class ChatDirector
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that a speak message be generated and delivered to all
|
||||
* users that occupy the place object that we currently occupy.
|
||||
*
|
||||
* @param message the contents of the speak message.
|
||||
*
|
||||
* @return an id which can be used to coordinate this speak request
|
||||
* with the response that will be delivered to all active chat
|
||||
* displays when it arrives, or -1 if we were unable to make the
|
||||
* request because we are not currently in a place.
|
||||
* Dispatches a {@link #requestSpeak(SpeakService,String,byte)} on the
|
||||
* place object that we currently occupy.
|
||||
*/
|
||||
public int requestSpeak (String message)
|
||||
public void requestSpeak (String message)
|
||||
{
|
||||
requestSpeak(message, DEFAULT_MODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a {@link #requestSpeak(SpeakService,String,byte)} on the
|
||||
* place object that we currently occupy.
|
||||
*/
|
||||
public void requestSpeak (String message, byte mode)
|
||||
{
|
||||
// make sure we're currently in a place
|
||||
if (_place == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// make sure they can say what they want to say
|
||||
for (Iterator iter = _validators.iterator(); iter.hasNext(); ) {
|
||||
if (!((ChatValidator) iter.next()).validateSpeak(message)) {
|
||||
return -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// dispatch a speak request on the active place object
|
||||
int reqid =
|
||||
_ctx.getClient().getInvocationDirector().nextInvocationId();
|
||||
Object[] args = new Object[] { new Integer(reqid), message };
|
||||
MessageEvent mevt = new MessageEvent(
|
||||
_place.getOid(), SPEAK_REQUEST, args);
|
||||
_ctx.getDObjectManager().postEvent(mevt);
|
||||
// TODO: when this gets changed such that we actually validate
|
||||
// this on the server, we have to make sure that the
|
||||
// user is not on a portal before we allow the 'shout' to go through
|
||||
return reqid;
|
||||
requestSpeak(_place.speakService, message, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that a speak message with the specified mode be generated
|
||||
* and delivered via the supplied speak service instance (which will
|
||||
* be associated with a particular "speak object"). The message will
|
||||
* first be validated by all registered {@link ChatValidator}s (and
|
||||
* possibly vetoed) before being dispatched.
|
||||
*
|
||||
* @param speakService the speak service to use when generating the
|
||||
* speak request.
|
||||
* @param message the contents of the speak message.
|
||||
* @param mode a speech mode that will be interpreted by the {@link
|
||||
* ChatDisplay} implementations that eventually display this speak
|
||||
* message.
|
||||
*/
|
||||
public void requestSpeak (
|
||||
SpeakService speakService, String message, byte mode)
|
||||
{
|
||||
// make sure they can say what they want to say
|
||||
for (Iterator iter = _validators.iterator(); iter.hasNext(); ) {
|
||||
if (!((ChatValidator) iter.next()).validateSpeak(message)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// dispatch a speak request using the supplied speak service
|
||||
speakService.speak(_ctx.getClient(), message, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,26 +276,34 @@ public class ChatDirector
|
||||
* @param target the username of the user to which the tell message
|
||||
* should be delivered.
|
||||
* @param message the contents of the tell message.
|
||||
*
|
||||
* @return an id which can be used to coordinate this request with the
|
||||
* tell response that will be delivered to all active chat displays
|
||||
* when it arrives.
|
||||
*/
|
||||
public int requestTell (String target, String message)
|
||||
public void requestTell (final String target, final String message)
|
||||
{
|
||||
// make sure they can say what they want to say
|
||||
for (Iterator iter = _validators.iterator(); iter.hasNext(); ) {
|
||||
if (!((ChatValidator) iter.next()).validateTell(
|
||||
target, message)) {
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int invid = ChatService.tell(_ctx.getClient(), target, message, this);
|
||||
// cache the tell info for use when reporting success or failure
|
||||
// to our various chat displays
|
||||
_tells.put(invid, new Tuple(target, message));
|
||||
return invid;
|
||||
// create a listener that will report success or failure
|
||||
ChatService.TellListener listener = new ChatService.TellListener() {
|
||||
public void tellSucceeded () {
|
||||
String msg = MessageBundle.tcompose(
|
||||
"m.told_format", target, message);
|
||||
displayFeedbackMessage(_bundle, msg);
|
||||
addChatter(target);
|
||||
}
|
||||
|
||||
public void requestFailed (String reason) {
|
||||
String msg =
|
||||
MessageBundle.compose("m.tell_failed", target, reason);
|
||||
displayFeedbackMessage(_bundle, msg);
|
||||
}
|
||||
};
|
||||
|
||||
_cservice.tell(_ctx.getClient(), target, message, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,6 +330,13 @@ public class ChatDirector
|
||||
_auxes.remove(source.getOid());
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
protected void fetchServices (Client client)
|
||||
{
|
||||
// get a handle on our chat service
|
||||
_cservice = (ChatService)client.requireService(ChatService.class);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean locationMayChange (int placeId)
|
||||
{
|
||||
@@ -340,88 +369,33 @@ public class ChatDirector
|
||||
public void messageReceived (MessageEvent event)
|
||||
{
|
||||
String name = event.getName();
|
||||
if (name.equals(ChatService.SPEAK_NOTIFICATION)) {
|
||||
if (name.equals(SPEAK_NOTIFICATION)) {
|
||||
handleSpeakMessage(
|
||||
getLocalType(event.getTargetOid()), event.getArgs());
|
||||
|
||||
} else if (name.equals(ChatService.SYSTEM_NOTIFICATION)) {
|
||||
} else if (name.equals(SYSTEM_NOTIFICATION)) {
|
||||
handleSystemMessage(
|
||||
getLocalType(event.getTargetOid()), event.getArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the invocation director when another client has requested
|
||||
* a tell message be delivered to this client.
|
||||
*/
|
||||
public void handleTellNotification (String source, String message)
|
||||
// documentation inherited from interface
|
||||
public void receivedTell (String speaker, String bundle, String message)
|
||||
{
|
||||
// bail if the speaker is blocked
|
||||
if (isBlocked(source)) {
|
||||
// ignore messages from blocked users
|
||||
if (isBlocked(speaker)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the message need be translated, do so
|
||||
if (bundle != null) {
|
||||
message = xlate(bundle, message);
|
||||
}
|
||||
|
||||
UserMessage um = new UserMessage(
|
||||
message, ChatCodes.TELL_CHAT_TYPE, source, ChatCodes.DEFAULT_MODE);
|
||||
message, ChatCodes.TELL_CHAT_TYPE, speaker, ChatCodes.DEFAULT_MODE);
|
||||
dispatchMessage(um);
|
||||
addChatter(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the invocation director when an entity on the server has
|
||||
* requested that we deliver a tell notification to this
|
||||
* client. Because the server generated the notification, displays
|
||||
* will want to translate the message itself using the supplied bundle
|
||||
* identifier.
|
||||
*/
|
||||
public void handleTellNotification (
|
||||
String source, String bundle, String message)
|
||||
{
|
||||
handleTellNotification(source, xlate(bundle, message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in response to a tell request that succeeded.
|
||||
*
|
||||
* @param invid the invocation id of the tell request.
|
||||
*/
|
||||
public void handleTellSucceeded (int invid)
|
||||
{
|
||||
// remove the tell info for the successful request
|
||||
Tuple tup = (Tuple)_tells.remove(invid);
|
||||
if (tup == null) {
|
||||
Log.warning("Notified of successful tell request but no " +
|
||||
"tell info available [invid=" + invid + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// pass this on to our chat displays
|
||||
String target = (String)tup.left, message = (String)tup.right;
|
||||
displayFeedbackMessage(
|
||||
_bundle, MessageBundle.tcompose("m.told_format", target, message));
|
||||
addChatter(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in response to a tell request that failed.
|
||||
*
|
||||
* @param invid the invocation id of the tell request.
|
||||
* @param reason the code that describes the reason for failure.
|
||||
*/
|
||||
public void handleTellFailed (int invid, String reason)
|
||||
{
|
||||
// remove the tell info for the failed request
|
||||
Tuple tup = (Tuple)_tells.remove(invid);
|
||||
if (tup == null) {
|
||||
Log.warning("Notified of failed tell request but no " +
|
||||
"tell info available [invid=" + invid + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// pass this on to our chat displays
|
||||
String target = (String)tup.left;
|
||||
displayFeedbackMessage(
|
||||
_bundle, MessageBundle.compose("m.tell_failed", target, reason));
|
||||
addChatter(speaker);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -519,9 +493,20 @@ public class ChatDirector
|
||||
return (_muter != null) && _muter.isMuted(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to assign unique ids to all speak requests.
|
||||
*/
|
||||
protected synchronized int nextRequestId ()
|
||||
{
|
||||
return _requestId++;
|
||||
}
|
||||
|
||||
/** Our active chat context. */
|
||||
protected CrowdContext _ctx;
|
||||
|
||||
/** Provides access to chat-related server-side services. */
|
||||
protected ChatService _cservice;
|
||||
|
||||
/** The message manager. */
|
||||
protected MessageManager _msgmgr;
|
||||
|
||||
@@ -544,16 +529,15 @@ public class ChatDirector
|
||||
/** An optionally present mutelist director. */
|
||||
protected MuteDirector _muter;
|
||||
|
||||
/** A cache of the target and message text associated with outstanding
|
||||
* tell chat requests. */
|
||||
protected HashIntMap _tells = new HashIntMap();
|
||||
|
||||
/** Usernames of users we've recently chatted with. */
|
||||
protected LinkedList _chatters = new LinkedList();
|
||||
|
||||
/** Observers that are watching our chatters list. */
|
||||
protected ArrayList _chatterObservers = new ArrayList();
|
||||
|
||||
/** Used by {@link #nextRequestId}. */
|
||||
protected int _requestId;
|
||||
|
||||
/** The maximum number of chatter usernames to track. */
|
||||
protected static final int MAX_CHATTERS = 6;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// $Id: ChatReceiver.java,v 1.3 2002/08/14 19:07:49 mdb Exp $
|
||||
|
||||
package com.threerings.crowd.chat;
|
||||
|
||||
import com.threerings.presents.client.InvocationReceiver;
|
||||
|
||||
/**
|
||||
* Defines, for the chat services, a set of notifications delivered
|
||||
* asynchronously by the server to the client.
|
||||
*/
|
||||
public interface ChatReceiver extends InvocationReceiver
|
||||
{
|
||||
/**
|
||||
* Called when a tell message is received from another player on the
|
||||
* server.
|
||||
*
|
||||
* @param speaker the username of the user from which this message
|
||||
* originated.
|
||||
* @param bundle if non-null, a bundle that should be used to
|
||||
* translate the text of the tell message. This is generally only used
|
||||
* when some server entity originates the tell message rather than
|
||||
* another user. The server entity might then wish for its tell
|
||||
* message to be translated into a language appropriate for the
|
||||
* receiver. Such luxuries are not available for human to human
|
||||
* conversation, alas.
|
||||
* @param message the text of the tell message.
|
||||
*/
|
||||
public void receivedTell (String speaker, String bundle, String message);
|
||||
}
|
||||
@@ -1,22 +1,31 @@
|
||||
//
|
||||
// $Id: ChatService.java,v 1.7 2002/05/15 23:54:34 mdb Exp $
|
||||
// $Id: ChatService.java,v 1.8 2002/08/14 19:07:49 mdb Exp $
|
||||
|
||||
package com.threerings.crowd.chat;
|
||||
|
||||
import com.threerings.presents.client.Client;
|
||||
import com.threerings.presents.client.InvocationDirector;
|
||||
import com.threerings.crowd.Log;
|
||||
import com.threerings.presents.client.InvocationService;
|
||||
|
||||
/**
|
||||
* The chat services provide a mechanism by which the client can broadcast
|
||||
* chat messages to all clients that are subscribed to a particular place
|
||||
* object or directly to a particular client. These services should not be
|
||||
* used directly, but instead should be accessed via the chat director.
|
||||
*
|
||||
* @see ChatDirector
|
||||
* used directly, but instead should be accessed via the {@link
|
||||
* ChatDirector}.
|
||||
*/
|
||||
public class ChatService implements ChatCodes
|
||||
public interface ChatService extends InvocationService
|
||||
{
|
||||
/**
|
||||
* Used to communicate the response to a {@link #tell} request.
|
||||
*/
|
||||
public static interface TellListener extends InvocationListener
|
||||
{
|
||||
/**
|
||||
* Communicates the response to a {@link #tell} request.
|
||||
*/
|
||||
public void tellSucceeded ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that a tell message be delivered to the user with username
|
||||
* equal to <code>target</code>.
|
||||
@@ -25,18 +34,8 @@ public class ChatService implements ChatCodes
|
||||
* @param target the username of the user to which the tell message
|
||||
* should be delivered.
|
||||
* @param message the contents of the message.
|
||||
* @param rsptarget the chat director reference that will receive the
|
||||
* tell response.
|
||||
*
|
||||
* @return the invocation request id of the generated tell request.
|
||||
* @param listener the reference that will receive the tell response.
|
||||
*/
|
||||
public static int tell (Client client, String target, String message,
|
||||
ChatDirector rsptarget)
|
||||
{
|
||||
InvocationDirector invdir = client.getInvocationDirector();
|
||||
Object[] args = new Object[] { target, message };
|
||||
Log.debug("Sending tell request [tgt=" + target +
|
||||
", msg=" + message + "].");
|
||||
return invdir.invoke(MODULE_NAME, TELL_REQUEST, args, rsptarget);
|
||||
}
|
||||
public void tell (Client client, String target, String message,
|
||||
TellListener listener);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// $Id: SpeakService.java,v 1.1 2002/08/14 19:07:49 mdb Exp $
|
||||
|
||||
package com.threerings.crowd.chat;
|
||||
|
||||
import com.threerings.presents.client.Client;
|
||||
import com.threerings.presents.client.InvocationService;
|
||||
|
||||
/**
|
||||
* Provides a means by which "speaking" can be allowed among subscribers
|
||||
* of a particular distributed object.
|
||||
*/
|
||||
public interface SpeakService extends InvocationService
|
||||
{
|
||||
/**
|
||||
* Issues a request to speak "on" the distributed object via which
|
||||
* this speak service was provided.
|
||||
*
|
||||
* @param message the message to be spoken.
|
||||
* @param mode the "mode" of the message. This is an opaque value that
|
||||
* will be passed back down via the {@link ChatDirector} to the {@link
|
||||
* ChatDisplay} implementations which can interpret it in an
|
||||
* application specific manner. It's useful for differentiating
|
||||
* between regular speech, emotes, etc.
|
||||
*/
|
||||
public void speak (Client client, String message, byte mode);
|
||||
}
|
||||
Reference in New Issue
Block a user