Managing Clients of Perspectives

Overview

As we've watched several applications build on top of twisted.cred and Perspective Broker, we've seen several models of interaction between Perspectives and the clients which connect to them. In the future, these patterns may be codified by support classes in the framework, but for now we shall just document them here. They are:

Clientless Perspective

in which the Perspective remains oblivious of the fact that clients attach to it.

Single Client

in which no more than one client is attached to a Perspective. There are two sub-categories, based on how this limit is enforced:

Multiple Client

in which the Perspective keeps a list of clients instead of a single one. The clients all share this Perspective, the actions of any may effect the perspective for all. (Seen in twisted.manhole.)

Anonymous Clients

where any number of clients may connect to the service using a particular perspective name, but clients may not effect one another and any changes to the perspective do not persist.

explain or point to how clients get attached to perspectives (pb.connect, guard(?)).

Clientless Perspective

clientless.py

Needless to say, the ClientlessPerspective is not ideal for all applications. A common model for network applications is to have the client functioning as an observer of messages distributed by the server (i.e. chat services, build failure notification, etc.). For this purpose, the server needs maintain a list of observers on reachable clients. The Perspective class provides facilities for this, offering attached() and detached() methods which are called with references to clients connecting or disconnecting from the service.

Single Client

single.py

Here's a more complex example, using the more specialized brokerAttached method of Perspective Broker.

single-pb.py

Here's an example which attempts to enforce the single-client limit in a different manner:

single-kick.py

What do we learn?

In fact, it turns out to be hard to kick a client off a Perspective, because there's no way you can force them to lose the reference they hold. The best you can do is define a goodbye method on the client interface and hope they honor and implement it correctly. If the client is talking to you over a transport (as is the case with Perspective Broker), you can kick them off somewhat forcibly by closing the transport, but this is bad practice for several reasons. First, it requires knowing how to access and shut down the transport, which breaks some abstractions. Second, it's a damned inconsiderate thing to do if that transport may have been also carrying traffic for other services.

I can think of several lines along which you could develop from here:

Multiple Client

multiple.py

Anonymous Clients

Last item on the list: Anonymous perspectives. One way to do it would be to use a ClientlessPerspective or MultipleClientPerspective and promise to not have any methods that stored state on or otherwise modified the perspective instance so no client can interfere with any other. Another way to do it, without that restriction, would be to use disposable Perspectives:

unattachable.py

If you wanted to have all access to a Service be anonymous, you could make a service like this:

class AnonymousService(service.Service):
    class perspectiveClass(UnattachablePerspective):
        disposablePerspectiveClass = MyAnonymousPerspective
        # XXX: does this lazy subclassing work, or do you end up with a class
        # that isn't persistable because it's not module-level or something?

But to make only certain log-ins anonymous:

theService = Service(serviceName)
anonymousPerspective = UnattachablePerspective("anonymous")
anonymousPerspective.disposablePerspectiveClass = MyAnonymousPerspective
theService.addPerspective(anonymousPerspective)
# Set anonymous's password to the empty string:
anonymousPerspective.makeIdentity('')

Feedback

That's all for today, thanks for playing. We'd like to hear about how you're using this code! Questions, comments, reservations? Please send them to twisted-python@twistedmatrix.com.