[Twisted-Python] Perspective vs. Identity question

Brian Warner warner at lothar.com
Sat Sep 14 04:34:48 EDT 2002

So I'm trying to figure out the whole PB thing; I smell a lot of potential
there but haven't figured out enough to actually use it yet. I figured a
question here might start to clear up my confusion. I'll start with what I
think I know so that if I'm wrong someone can correct my understanding. I
intend to turn this into some kind of documentation so that my ignorance can
be used towards some greater good :).

I think I get the PB remote-method scheme up to the level demonstrated in
docs/examples/pbsimple.py (using pb.connect and remote_* methods). In trying
to figure out the Perspective/Identity layer (as in pbecho.py), what I've
figured out so far is:

 Application instances hold an Authorizer, usually a DefaultAuthorizer.

 A DefaultAuthorizer has a collection of Identity objects, each with a
 unique identityName. That collection doesn't have to be a static list:
 .getIdentityRequest() could be overridden to do some kind of asynchronous
 lookup (LDAP comes to mind).

 Each Identity has a username and a password. It also has a list of "keys"
 (.keyring), each of which is a (perspectivename, servicename) tuple.

 If the remote client knows both username and password for a given Identity,
 then they are allowed to ask that Identity for any perspective on its
 keyring by supplying a (servicename/perspectivename) pair. The
 identity.requestPerspectiveForKey() method is supposed to find the named
 Perspective (asynchronously), run .attach() on it, then give a reference to
 the client.

 Once the client has that remote reference, they can do any perspective_*
 method they like.

So my understanding breaks down in how this is all supposed to work in
practice. I keep thinking of it in terms of a login shell or game, where you
have a bunch of user accounts, and a user is using their client program to
connect in. Let's say there are two Services: Shell and Game, and that the
same users are allowed to connect to both. Then:

 Each user has one Identity object, with a username and password. These
 Identities could be created ahead of time (say, from /etc/passwd) and
 stored in the DefaultAuthorizer's list. Or, they might be created on the
 fly by a custom Authorizer class. The important thing is that
 .getIdentityRequest returns a valid Identity object when asked.

 Each user might talk to two potential Perpective objects. When user 'bob'
 is attached in to do shell stuff, he could use a Perspective called
 'bob_shell', which is part of the Shell service. (I think the
 perspectivename is scoped to the Service, so this could just be named
 'bob', but that would make this description confusing). When he is doing
 game stuff, he could use a Perspective called 'bob_game', part of the Game
 service. Presumably bob_shell and bob_game are instances of different
 subclasses of pb.Perspective, one which offers shell-like remote methods
 and the other offering game-like methods. The cross-user shared state that
 represents the communal game world could be stored up in the Game Service
 object, anything that needs to be shared between both the game and the
 shell could go in the overall Application object.

Now, how are those Perspectives supposed to be created? Do they get built
ahead of time (at the same time the Identities are made)? Are they supposed
to outlast the client connection?

In all the doc/example/ programs, a single Perspective is created ahead of
time, and then a single Identity is created from that Perspective, using the
.makeIdentity() utility method. The largest example I've been able to find
is twisted.words, but as far as I can tell it does the same thing.. I think
the words.Participant (subclassed from pb.Perspective) hangs around all the
time whether or not the client is attached (it has a .status flag that
starts as OFFLINE), and the perspectives are always created ahead of time
(tap/words.py does svc.createPerspective(n).makeIdentity(pw)) based upon who
is allowed to connect.

I can see that the Perspective is kind of an in-server proxy for the remote
user: the client can make it do anything they want (well, any perspective_*
methods at least), and the perspective can outlast the client's connection
(its .attached/.detached are called to let it know when the client comes and
goes). But if it isn't supposed to (or doesn't need to) outlive the
connection, then must it still be created ahead of time? Is
identity.requestPerspectiveForKey() allowed to create new perspective
objects on the fly?

Sorry for the length. Tell me if I'm on the right track here.. if so, I'll
try to put together some kind of multi-Perspective example program (maybe
the telnet/game thing I just described) with a big how-it-works writeup,
something that explains the concepts I just went over. An example+writeup
like that would have helped / will help me figure out this part of Twisted..
maybe it could help others too.

thanks much,
 -Brian, twisting a little bit more each day

More information about the Twisted-Python mailing list