This commit is contained in:
locklainn.linden
2008-06-27 15:10:24 +00:00
committed by Salad Dais
parent 57f8cc2898
commit 5bb135727d
16 changed files with 425 additions and 0 deletions

4
README.txt Normal file
View File

@@ -0,0 +1,4 @@
Introduction
============

8
docs/HISTORY.txt Normal file
View File

@@ -0,0 +1,8 @@
Changelog
=========
1.0 - Unreleased
----------------
* Initial release

6
pyogp/__init__.py Normal file
View File

@@ -0,0 +1,6 @@
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

6
pyogp/lib/__init__.py Normal file
View File

@@ -0,0 +1,6 @@
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

View File

46
pyogp/lib/base/agent.py Normal file
View File

@@ -0,0 +1,46 @@
from zope.interface import implements
from zope.component import adapts
from interfaces import IAgent, IPlaceAvatarAdapter
class Agent(object):
"""an OGP agent"""
implements(IAgent)
def __init__(self, agentdomain):
"""initialize this agent"""
self.agentdomain = agentdomain
class PlaceAvatarAdapter(object):
"""handles placing an avatar for an agent object"""
implements(IPlaceAvatarAdapter)
adapts(IAgent)
def __init__(self, agent):
"""initialize this adapter"""
self.agent = agent
# let's retrieve the cap we need
self.seed_cap = self.agent.agentdomain.seed_cap # ISeedCapability
self.place_avatar_cap = self.seed_cap.get(['place_avatar'])['place_avatar']
def __call__(self, region):
"""initiate the placing process"""
region_uri = region.uri
payload = {'region_url' : region_uri }
result = self.place_avatar_cap(payload)
return result
# now we register this adapter so it can be used later:
from zope.component import provideAdapter
# register adapters for the HTML node
provideAdapter(PlaceAvatarAdapter)

View File

@@ -0,0 +1,43 @@
from agent import Agent
from interfaces import ICredentialSerializer
from caps import SeedCapability
import urllib2
# URL Opener for the agent domain login
#
class RedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_302(self, req, fp, code, msg, headers):
#ignore the redirect, grabbing the seed cap url from the headers
# TODO: add logging and error handling
return headers['location']
# post to auth.cgi, ignoring the built in redirect
AgentDomainLoginOpener = urllib2.build_opener(RedirectHandler())
class AgentDomain(object):
"""an agent domain endpoint"""
def __init__(self,uri):
"""initialize the agent domain endpoint"""
self.uri = uri
def login(self, credentials):
"""login to the agent domain and return an agent object"""
serializer = ICredentialSerializer(credentials) # convert to string via adapter
payload = serializer.serialize()
headers = serializer.headers
print payload, headers
# now create the request. We assume for now that self.uri is the login uri
# TODO: make this pluggable so we can use other transports like eventlet in the future
# TODO: add logging and error handling
request = urllib2.Request(self.uri,payload,headers)
seed_cap_url = AgentDomainLoginOpener.open(request)
self.seed_cap = SeedCapability('seed_cap', seed_cap_url)
return Agent(self)

58
pyogp/lib/base/caps.py Normal file
View File

@@ -0,0 +1,58 @@
from zope.interface import implements
import urllib2
from indra.base import llsd
from interfaces import ICapability, ISeedCapability
class Capability(object):
"""models a capability"""
implements(ICapability)
def __init__(self, name, private_url):
"""initialize the capability"""
self.name = name
self.private_url = private_url
def __call__(self,payload,custom_headers={}):
"""call this capability, return the parsed result"""
headers = {"Content-type" : "application/llsd+xml"}
headers.update(custom_headers)
llsd_payload = llsd.format_xml(payload)
# TODO: better errorhandling with own exceptions
try:
request = urllib2.Request(self.private_url, llsd_payload, headers)
result = urllib2.urlopen(request).read()
except urllib2.HTTPError, e:
print "** failure while calling cap:",
print e.read()
raise
return llsd.parse(result)
class SeedCapability(Capability):
"""a seed capability which is able to retrieve other capabilities"""
implements(ISeedCapability)
def get(self, names=[]):
"""if this is a seed cap we can retrieve other caps here"""
payload = {'caps':names}
parsed_result = self(payload)['caps']
caps = {}
for name in names:
# TODO: some caps might be seed caps, how do we know?
caps[name]=Capability(name, parsed_result[name])
return caps

View File

@@ -0,0 +1,54 @@
from zope.interface import implements
from zope.component import adapts
from indra.base import llsd
from interfaces import IPlainPasswordCredential, ICredentialSerializer
class PlainPasswordCredential(object):
"""a plain password credential"""
implements(IPlainPasswordCredential)
def __init__(self, firstname, lastname, password):
"""initialize this credential"""
self.firstname = firstname
self.lastname = lastname
self.password = password
# an adapter to serialize this to LLSD
class PlainPasswordLLSDSerializer(object):
"""converts a plain password credential to LLSD"""
implements(ICredentialSerializer)
adapts(IPlainPasswordCredential)
def __init__(self, context):
"""initialize this adapter by storing the context (the credential)"""
self.context = context
def serialize(self):
"""return the credential as a string"""
loginparams={
'password' : self.context.password,
'lastname' : self.context.lastname,
'firstname' : self.context.firstname
}
llsdlist = llsd.format_xml(loginparams)
return llsdlist
@property
def headers(self):
"""return HTTP headers needed here"""
return {"Content-type" : "application/llsd+xml"}
# now we register this adapter so it can be used later:
from zope.component import provideAdapter
# register adapters for the HTML node
provideAdapter(PlainPasswordLLSDSerializer)

46
pyogp/lib/base/example.py Normal file
View File

@@ -0,0 +1,46 @@
from pyogp.lib.base.credentials import PlainPasswordCredential
from pyogp.lib.base.agentdomain import AgentDomain
from pyogp.lib.base.regiondomain import Region
from pyogp.lib.base.interfaces import IPlaceAvatarAdapter
import getpass, sys
from optparse import OptionParser
class ExampleLogin(object):
def login(self):
parser = OptionParser()
parser.add_option("-a", "--agentdomain", dest="loginuri", default="https://login1.aditi.lindenlab.com/cgi-bin/auth.cgi",
help="URI of Agent Domain")
parser.add_option("-r", "--region", dest="regionuri", default="http://sim1.vaak.lindenlab.com:13000",
help="URI of Region to connect to")
(options, args) = parser.parse_args()
firstname = args[0]
lastname = args[1]
password = getpass.getpass()
credentials = PlainPasswordCredential(firstname, lastname, password)
agentdomain = AgentDomain(options.loginuri)
agent = agentdomain.login(credentials)
print "logged in, we now have an agent: ", agent
place = IPlaceAvatarAdapter(agent)
region = Region(options.regionuri)
print "now we try to place the avatar on a region"
avatar = place(region)
#avatar.establish_presence()
#
def main():
return ExampleLogin().login()
if __name__=="__main__":
main()

View File

@@ -0,0 +1,69 @@
from zope.interface import Interface, Attribute
class ICredential(Interface):
"""base interface for credentials"""
class IPlainPasswordCredential(ICredential):
"""a plain password credential"""
firstname = Attribute("""first name of avatar""")
lastname = Attribute("""last name of avatar""")
password = Attribute("""plain password""")
class ICredentialSerializer(Interface):
"""converts a credential to a serialized format for sending it over the network"""
def serialize():
"""return a serialized string"""
def headers():
"""return headers eventually needed for sending it out"""
class IAgent(Interface):
"""models an agent"""
agentdomain = Attribute("""the agent domain endpoint""")
class IRegion(Interface):
"""a region endpoint"""
def place_avatar(agent):
"""place an avatar on this region, returns IAvatar"""
class IAvatar(Interface):
"""an OGP avatar (region representation of an agent)"""
def establish_presence():
"""for now it will do a loop to establish a presence on a region"""
class IPlaceAvatarAdapter(Interface):
"""adapts an agents to a method which can place an avatar on a region"""
def __call__(region):
"""takes a region objects and tries to place the agent there as an avatar
return an IAvatar"""
class ICapability(Interface):
"""a capability"""
name = Attribute('''name of the capability''')
private_url = Attribute('''private url of this capability''')
def __call__(payload):
"""call this capability
payload -- the payload as python dictionary
returns a python dictionary with the results
"""
class ISeedCapability(ICapability):
"""a seed capability which is able to retrieve further capabilities"""
def get(names=[]):
"""retrieve the given set of named capabilities
returns a dict of ICapabilty objects keyed by their name"""

View File

@@ -0,0 +1,14 @@
from zope.interface import implements
from interfaces import IRegion
class Region(object):
"""models a region endpoint"""
implements(IRegion)
def __init__(self, uri):
"""initialize the region with the region uri"""
self.uri = uri

View File

@@ -0,0 +1,30 @@
Login
=====
>>> from pyogp.lib.base.credentials import PlainPasswordCredential
>>> from pyogp.lib.base.agentdomain import AgentDomain
>>> from pyogp.lib.base.regiondomain import Region
First we create some credentials:
>>> credentials = PlainPasswordCredential('Firstname', 'Lastname', 'password')
Then we need some agent domain to connect to. This might automatically retrieve some XRDS file to get the actual login endpoint:
>>> agentdomain = AgentDomain('http://agent.domain')
Now we can use both to get an agent object (which transparently handles capabilities etc.):
>>> agent = AgentDomain.login(credentials)
The next step is to use this agent to actually place the avatar somewhere. We therefor need a region:
>>> region = Region('http://region.uri')
Note that we can also first retrieve a RegionDomain object and ask this for possible regions and a map etc.
So let's place the agent in form of an avatar there (or try it at least):
>>> avatar = region.place_avatar(agent)
Now we should establish a presence there:
avatar.establish_presence()
As this is an infinite loop the question is how this could be handled. Maybe in a different thread?

3
setup.cfg Normal file
View File

@@ -0,0 +1,3 @@
[egg_info]
tag_build = dev
tag_svn_revision = true

37
setup.py Normal file
View File

@@ -0,0 +1,37 @@
from setuptools import setup, find_packages
import os
version = '1.0'
setup(name='pyogp.lib.base',
version=version,
description="basic pyogp library package",
long_description=open("README.txt").read() + "\n" +
open(os.path.join("docs", "HISTORY.txt")).read(),
# Get more strings from http://www.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
"Programming Language :: Python",
"Topic :: Software Development :: Libraries :: Python Modules",
],
keywords='pyogp login awg virtualworlds',
author='Christian Scholz',
author_email='mrtopf@gmail.com',
url='',
license='GPL',
packages=find_packages(exclude=['ez_setup']),
namespace_packages=['pyogp', 'pyogp.lib'],
include_package_data=True,
zip_safe=False,
install_requires=[
'setuptools',
'zope.interface',
'zope.component'
# -*- Extra requirements: -*-
],
entry_points={
'console_scripts': [
'login = pyogp.lib.base.example:main',
],
},
)

1
zopeskel.txt Normal file
View File

@@ -0,0 +1 @@
nested_namespace