As we've watched several applications build on top of twisted.cred
and Perspective
Broker, we've seen several models of interaction between Perspective
s 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:
in which the Perspective remains oblivious of the fact that clients attach to it.
in which no more than one client is attached to a Perspective. There are two sub-categories, based on how this limit is enforced:
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
.)
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(?)).
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.
Here's a more complex example, using the more specialized brokerAttached
method of Perspective Broker.
Here's an example which attempts to enforce the single-client limit in a different manner:
single-kick.pyWhat do we learn?
twisted.words
, the only system that
ships with Twisted which uses Perspectives in Perspective Broker,
is a lousy example. ;)detached
is not sufficient to kick a client off.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:
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:
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('')
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.