Hi!
I thought I give you a little overview about the types of objects we
have right now in the lib after my refactoring:
Credentials
-----------
a class which mainly stores some credential and has some adapter
which knows how to turn this into LLSD (or at some point maybe JSON).
There can be many types, we now only have PlainPasswordCredential.
Can be found in credentials.py
AgentDomain
-----------
This models the endpoint of an agent domain. Right now mainly used
for login and receiving the seedcap. It is instantiated with the
login URL but might at some point be some URL which has a
discoverable service catalogue which then contains the login url.
Can be instantiated with ad = AgentDomain(url)
It only has one method so far: login(credentials)
Any credential object can be used here as long as it has an adapter
registered which can turn it into LLSD.
login() returns an Agent object.
It's implemented in agentdomain.py
Agent
-----
An Agent right now mainly contains a pointer to it's agent domain.
My idea was that for all other functionality we adapat (cast) it to
some adapter which does the work. In agent.py is not only the Agent
class defined but also the adapter for placing the agent on a region.
You can do it like this:
>>> place = IPlaceAvatarAdapter(agent)
place is now the adapter which can be used to place it on a region.
When you instantiate the IPlaceAvatarAdapter() by doing the above it
will automatically retrieve the place avatar cap via the agent's seed
cap and store it internally. It has a method __call__() method which
does the actual work and calls that cap.
Region
------
Here I am wondering (and we did so at todays AWGroupies meetup) if
this shouldn't be a RegionDomain because an RD is missing right now
in the diagrams. Maybe request_rez_avatar() should be directed to the
domain and returns a cap of the region in question? But is not a
pyogp related issue.
So a Region object in our case take a region url:
>>> region = Region("http://sim1....:17262")
It's define in regiondomain.py and really only stores that url.
You can use that region object and pass it to the place adapter to retr
Capabilities and Seed Capabilities
----------------------------------
Capability is the more general class and SeedCapability derives from
it (caps.py). I used a __call__() method to actually call the
capability (sending payload to the cap url stored in private_url
which probably is the public url, so it's wrong names ;-)).
That means you can use it like this:
>>> cap =
Capability("place_avatar","http://someserver.com/cap/87227628762827628762827628726876")
This just stores the data.
>>> cap(payload)
will then send the payload to this URL and return the result.
The SeedCapability can do the same of course but has a get() method
additionally which takes a list of cap names to retrieve. It will
return a dictionary with name => Capability() entries.
So this is what we have right now. So far it seemed to work good for me.
Some notes though:
- for the payload which is send to a cap url we can maybe define a
default adapter which converts it to LLSD. This would enable us later
to register a new one which converts to something else without
changing the library (e.g. JSON). This means we cannot use a
dictionary but we might need to use some Custom Dictionary class
which has the interface attached (UserDict is the super class then I
think). Should be fairly simple.
- When retrieving caps I don't know right now which one of these are
seed caps themselves and should be SeedCapability objects instead. We
can put a list of those defined in the spec in the code of course or
maybe we can extend the cap mechanism to flag those? (and I still
don't like them to be honest because of the extra roundtrip and new
concept to new devs. ).
- How does the RegionDomain come into play?
- How would those http calls look under eventlet? This might be good
to know so we can factor it out. The networking part could be a
utility so that you can say:
>>> from interfaces import INetwork
>>> network = getUtility(INetwork)
>>> request = network.Request(url, data, headers)
>>> response = network.open(request)
This now is a 1:1 mapping from urllib2 which makes it quite easy then.
I guess at least with those eventlet standard lib hooks not much will
be different except that it's not blocking. Probably that's enough as
things like spawn() etc. might more used on a higher level then.
The only thing needed then would be to reimplement the INetwork
utility and register it.
- Where do we put component registrations? Usually it's good to know
what adapter is actually used when saying IPlaceAvatarAdapter(agent).
This is now "hidden" in agent.py and the credential on in credential.py.
I would suggest to move those out and put them into a registration.py
file. We can also use ZCML (an XML syntax for doing that) but I first
need to check how that works (which will be easy at EuroPython with
all those experts :-) ).
This would mean that for understanding the components you would
1. look into interfaces.py what actually is defined
2. look into registration.py for looking where it is implemented
Then again the easiest way to understand it should be a doctest and
the above description of AgentDomain and Agent etc. might be such a
doctest already.
Ok, enough, next SL meetup :)
-- Christian