Revamped chat handling a bit:

- the ChatProvider is now a proper singleton rather than providing static
methods for everything (it is accessed through CrowdServer.chatprov)
- it can now be extended to create a custom UserMessage for tells (which can
contain avatar information on systems that want to show an avatar on the
receipt of a tell)
- the ChatProvider API was tidied up a bit as some methods had been addded over
time that were not sufficiently general purpose so their callers will be
changed to use the general purpose APIs.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4251 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2006-07-06 00:22:12 +00:00
parent ef86404ed8
commit 05cef39f63
7 changed files with 117 additions and 110 deletions
@@ -74,32 +74,10 @@ public class ChatProvider
*
* @return true if the tell was delivered, false otherwise.
*/
public boolean forwardTell (Name teller, Name target, String message,
public boolean forwardTell (UserMessage message, Name target,
TellListener listener);
}
/**
* Set the auto tell responder for the chat provider. Only one auto
* responder is allowed. <em>Note:</em> this only works for same-server
* tells. If the tell is forwarded to another server, no auto-response
* opportunity is provided (because we never have both body objects in the
* same place).
*/
public static void setTellAutoResponder (TellAutoResponder autoRespond)
{
_autoRespond = autoRespond;
}
/**
* Configures the tell forwarded for the chat provider. This is used by the
* Crowd peer services to forward tells between servers in a multi-server
* cluster.
*/
public static void setTellForwarder (TellForwarder forwarder)
{
_tellForwarder = forwarder;
}
/**
* Set an object to which all broadcasts should be sent, rather
* than iterating over the place objects and sending to each of them.
@@ -107,22 +85,41 @@ public class ChatProvider
* @param object an object to send all broadcasts, or null to send to
* each place object instead.
*/
public static void setAlternateBroadcastObject (DObject object)
public void setAlternateBroadcastObject (DObject object)
{
_broadcastObject = object;
}
/**
* Set the auto tell responder for the chat provider. Only one auto
* responder is allowed. <em>Note:</em> this only works for same-server
* tells. If the tell is forwarded to another server, no auto-response
* opportunity is provided (because we never have both body objects in the
* same place).
*/
public void setTellAutoResponder (TellAutoResponder autoRespond)
{
_autoRespond = autoRespond;
}
/**
* Configures the tell forwarded for the chat provider. This is used by the
* Crowd peer services to forward tells between servers in a multi-server
* cluster.
*/
public void setTellForwarder (TellForwarder forwarder)
{
_tellForwarder = forwarder;
}
/**
* Initializes the chat services and registers a chat provider with
* the invocation manager.
*/
public static void init (InvocationManager invmgr, DObjectManager omgr)
public void init (InvocationManager invmgr, DObjectManager omgr)
{
_omgr = omgr;
// register a chat provider with the invocation manager
invmgr.registerDispatcher(new ChatDispatcher(
new ChatProvider()), true);
invmgr.registerDispatcher(new ChatDispatcher(this), true);
}
/**
@@ -141,7 +138,7 @@ public class ChatProvider
}
// deliver the tell message to the target
deliverTell(source.getVisibleName(), target, message, listener);
deliverTell(createTellMessage(source, message), target, listener);
// inform the auto-responder if needed
BodyObject targobj;
@@ -164,10 +161,20 @@ public class ChatProvider
if (errmsg != null) {
throw new InvocationException(errmsg);
}
broadcast(body.getVisibleName(), null, message, false);
}
/**
* Processes a {@link ChatService#away} request.
*/
public void away (ClientObject caller, String message)
{
BodyObject body = (BodyObject)caller;
// we modify this field via an invocation service request because
// a body object is not modifiable by the client
body.setAwayMessage(message);
}
/**
* Broadcast the specified message to all places in the game.
*
@@ -178,7 +185,7 @@ public class ChatProvider
* @param attention if true, the message is sent as ATTENTION level,
* otherwise as INFO. Ignored if from is non-null.
*/
public static void broadcast (Name from, String bundle, String msg,
public void broadcast (Name from, String bundle, String msg,
boolean attention)
{
if (_broadcastObject != null) {
@@ -196,42 +203,12 @@ public class ChatProvider
}
/**
* Direct a broadcast to the specified object.
* Delivers a tell message to the specified target and notifies the
* supplied listener of the result. It is assumed that the teller has
* already been permissions checked.
*/
protected static void broadcastTo (DObject object,
Name from, String bundle, String msg, boolean attention)
{
if (from == null) {
if (attention) {
SpeakProvider.sendAttention(object, bundle, msg);
} else {
SpeakProvider.sendInfo(object, bundle, msg);
}
} else {
SpeakProvider.sendSpeak(object, from, bundle, msg,
BROADCAST_MODE);
}
}
/**
* Processes a {@link ChatService#away} request.
*/
public void away (ClientObject caller, String message)
{
BodyObject body = (BodyObject)caller;
// we modify this field via an invocation service request because
// a body object is not modifiable by the client
body.setAwayMessage(message);
}
/**
* Delivers a tell message from the specified teller to the specified
* target. It is assumed that the teller has already been permissions
* checked.
*/
public static void deliverTell (Name teller, Name target, String message,
TellListener listener)
public void deliverTell (UserMessage message, Name target,
TellListener listener)
throws InvocationException
{
// make sure the target user is online
@@ -239,7 +216,7 @@ public class ChatProvider
if (tobj == null) {
// if we have a forwarder configured, try forwarding the tell
if (_tellForwarder != null &&
_tellForwarder.forwardTell(teller, target, message, listener)) {
_tellForwarder.forwardTell(message, target, listener)) {
return;
}
throw new InvocationException(USER_NOT_ONLINE);
@@ -254,7 +231,7 @@ public class ChatProvider
}
// deliver a tell notification to the target player
sendTellMessage(tobj, teller, null, message);
deliverTell(tobj, message);
// let the teller know it went ok
long idle = 0L;
@@ -269,39 +246,52 @@ public class ChatProvider
}
/**
* Delivers a tell notification to the specified target player,
* originating with the specified speaker.
*
* @param target the body object of the user that will receive the
* tell message.
* @param speaker the username of the user that generated the message
* (or some special speaker name for server messages).
* @param bundle the bundle identifier that will be used by the client
* to translate the message text (this would be null in all cases
* except where the message originated from some server entity that
* was "faking" a tell to a real player).
* @param message the text of the chat message.
* Delivers a tell notification to the specified target player. It is
* assumed that the message is coming from some server entity and need not
* be permissions checked or notified of the result.
*/
public static void sendTellMessage (
BodyObject target, Name speaker, String bundle, String message)
public void deliverTell (BodyObject target, UserMessage message)
{
UserMessage msg = new UserMessage(
message, bundle, speaker, DEFAULT_MODE);
SpeakProvider.sendMessage(target, msg);
SpeakProvider.sendMessage(target, message);
// note that the teller "heard" what they said
SpeakProvider.noteMessage(speaker, msg);
SpeakProvider.noteMessage(message.speaker, message);
}
/** The distributed object manager used by the chat services. */
protected static DObjectManager _omgr;
/**
* Used to create a {@link UserMessage} for the supplied sender.
*/
protected UserMessage createTellMessage (BodyObject source, String message)
{
return new UserMessage(
message, null, source.getVisibleName(), DEFAULT_MODE);
}
/**
* Direct a broadcast to the specified object.
*/
protected void broadcastTo (DObject object, Name from, String bundle,
String msg, boolean attention)
{
if (from == null) {
if (attention) {
SpeakProvider.sendAttention(object, bundle, msg);
} else {
SpeakProvider.sendInfo(object, bundle, msg);
}
} else {
SpeakProvider.sendSpeak(object, from, bundle, msg,
BROADCAST_MODE);
}
}
/** Generates auto-responses to tells. May be null. */
protected static TellAutoResponder _autoRespond;
protected TellAutoResponder _autoRespond;
/** Forwards tells between servers. May be null. */
protected static TellForwarder _tellForwarder;
protected TellForwarder _tellForwarder;
/** An alternative object to which broadcasts should be sent. */
protected static DObject _broadcastObject;
protected DObject _broadcastObject;
}
@@ -27,6 +27,7 @@ import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.crowd.chat.client.ChatService;
import com.threerings.crowd.chat.data.UserMessage;
/**
* Bridges certain Crowd services between peers in a cluster configuration.
@@ -37,6 +38,6 @@ public interface CrowdPeerService extends InvocationService
* Used to forward a tell request to the server on which the destination
* user actually occupies.
*/
public void deliverTell (Client client, Name teller, Name target,
String message, ChatService.TellListener listener);
public void deliverTell (Client client, UserMessage message, Name target,
ChatService.TellListener listener);
}
@@ -23,6 +23,7 @@ package com.threerings.crowd.peer.data;
import com.threerings.crowd.chat.client.ChatService;
import com.threerings.crowd.chat.data.ChatMarshaller;
import com.threerings.crowd.chat.data.UserMessage;
import com.threerings.crowd.peer.client.CrowdPeerService;
import com.threerings.presents.client.Client;
import com.threerings.presents.data.InvocationMarshaller;
@@ -43,12 +44,12 @@ public class CrowdPeerMarshaller extends InvocationMarshaller
public static final int DELIVER_TELL = 1;
// documentation inherited from interface
public void deliverTell (Client arg1, Name arg2, Name arg3, String arg4, ChatService.TellListener arg5)
public void deliverTell (Client arg1, UserMessage arg2, Name arg3, ChatService.TellListener arg4)
{
ChatMarshaller.TellMarshaller listener5 = new ChatMarshaller.TellMarshaller();
listener5.listener = arg5;
ChatMarshaller.TellMarshaller listener4 = new ChatMarshaller.TellMarshaller();
listener4.listener = arg4;
sendRequest(arg1, DELIVER_TELL, new Object[] {
arg2, arg3, arg4, listener5
arg2, arg3, listener4
});
}
@@ -23,6 +23,7 @@ package com.threerings.crowd.peer.server;
import com.threerings.crowd.chat.client.ChatService;
import com.threerings.crowd.chat.data.ChatMarshaller;
import com.threerings.crowd.chat.data.UserMessage;
import com.threerings.crowd.peer.client.CrowdPeerService;
import com.threerings.crowd.peer.data.CrowdPeerMarshaller;
import com.threerings.presents.client.Client;
@@ -61,7 +62,7 @@ public class CrowdPeerDispatcher extends InvocationDispatcher
case CrowdPeerMarshaller.DELIVER_TELL:
((CrowdPeerProvider)provider).deliverTell(
source,
(Name)args[0], (Name)args[1], (String)args[2], (ChatService.TellListener)args[3]
(UserMessage)args[0], (Name)args[1], (ChatService.TellListener)args[2]
);
return;
@@ -37,6 +37,7 @@ import com.threerings.presents.peer.server.PeerManager;
import com.threerings.crowd.chat.client.ChatService;
import com.threerings.crowd.chat.data.ChatMessage;
import com.threerings.crowd.chat.data.UserMessage;
import com.threerings.crowd.chat.server.ChatProvider;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.server.CrowdServer;
@@ -62,17 +63,16 @@ public class CrowdPeerManager extends PeerManager
}
// documentation inherited from interface CrowdPeerProvider
public void deliverTell (ClientObject caller, Name teller, Name target,
String message, ChatService.TellListener listener)
public void deliverTell (ClientObject caller, UserMessage message,
Name target, ChatService.TellListener listener)
throws InvocationException
{
// the originating server has already permissions checked the teller,
// so we just forward the message as if it originated on this server
ChatProvider.deliverTell(teller, target, message, listener);
// we just forward the message as if it originated on this server
CrowdServer.chatprov.deliverTell(message, target, listener);
}
// documentation inherited from interface ChatProvider.TellForwarder
public boolean forwardTell (Name teller, Name target, String message,
public boolean forwardTell (UserMessage message, Name target,
ChatService.TellListener listener)
{
// look through our peer objects to see if the target user is online on
@@ -82,7 +82,7 @@ public class CrowdPeerManager extends PeerManager
CrowdClientInfo cinfo = (CrowdClientInfo)cnobj.clients.get(target);
if (cinfo != null) {
cnobj.crowdPeerService.deliverTell(
peer.getClient(), teller, target, message, listener);
peer.getClient(), message, target, listener);
return true;
}
}
@@ -101,7 +101,7 @@ public class CrowdPeerManager extends PeerManager
}
// clear our tell forwarder registration
ChatProvider.setTellForwarder(null);
CrowdServer.chatprov.setTellForwarder(null);
}
@Override // documentation inherited
@@ -116,7 +116,7 @@ public class CrowdPeerManager extends PeerManager
new CrowdPeerDispatcher(this), false));
// register ourselves as a tell forwarder
ChatProvider.setTellForwarder(this);
CrowdServer.chatprov.setTellForwarder(this);
}
@Override // documentation inherited
@@ -23,6 +23,7 @@ package com.threerings.crowd.peer.server;
import com.threerings.crowd.chat.client.ChatService;
import com.threerings.crowd.chat.data.ChatMarshaller;
import com.threerings.crowd.chat.data.UserMessage;
import com.threerings.crowd.peer.client.CrowdPeerService;
import com.threerings.presents.client.Client;
import com.threerings.presents.data.ClientObject;
@@ -38,6 +39,6 @@ public interface CrowdPeerProvider extends InvocationProvider
/**
* Handles a {@link CrowdPeerService#deliverTell} request.
*/
public void deliverTell (ClientObject caller, Name arg1, Name arg2, String arg3, ChatService.TellListener arg4)
public void deliverTell (ClientObject caller, UserMessage arg1, Name arg2, ChatService.TellListener arg3)
throws InvocationException;
}
@@ -46,6 +46,9 @@ public class CrowdServer extends PresentsServer
/** The place registry. */
public static PlaceRegistry plreg;
/** Our chat provider. */
public static ChatProvider chatprov;
/**
* Initializes all of the server services and prepares for operation.
*/
@@ -78,7 +81,8 @@ public class CrowdServer extends PresentsServer
BodyProvider.init(invmgr);
// initialize the chat services
ChatProvider.init(invmgr, omgr);
chatprov = createChatProvider();
chatprov.init(invmgr, omgr);
}
/**
@@ -90,6 +94,15 @@ public class CrowdServer extends PresentsServer
return new PlaceRegistry(invmgr, omgr);
}
/**
* Creates the {@link ChatProvider} we'll use to handle chat (or a
* derivation).
*/
protected ChatProvider createChatProvider ()
{
return new ChatProvider();
}
/**
* Allow derived instances to create a custom {@link BodyLocator}. If the
* system opts not to use {@link BodyObject#username} as a user's visible