[Twisted-Python] Perspective vs. Identity question
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
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.
-Brian, twisting a little bit more each day
More information about the Twisted-Python