merged branch mrtopf-grokified into trunk. For making it work I resolved some obvious conflicts and changed the message parser classes to new style classes.

This commit is contained in:
tao.takashi
2008-07-23 20:03:40 +00:00
committed by Salad Dais
parent 38c775429a
commit c3528af70e
21 changed files with 202 additions and 71 deletions

View File

@@ -2,7 +2,7 @@ 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
from pyogp.lib.base.interfaces import IPlaceAvatar
import getpass, sys
from optparse import OptionParser
@@ -43,7 +43,7 @@ class OGPLogin(object):
def placeAvatarCap(self):
""" actually gets the place_avatar cap and posts to it """
region = Region(self.regionuri)
place = IPlaceAvatarAdapter(self.agent)
place = IPlaceAvatar(self.agent)
self.avatar = place(region)
return self.avatar

View File

@@ -1,7 +1,9 @@
from zope.interface import implements
from zope.component import adapts
from interfaces import IAgent, IPlaceAvatarAdapter
from interfaces import IAgent
import grokcore.component as grok
class Agent(object):
"""an OGP agent"""
@@ -14,33 +16,5 @@ class Agent(object):
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

@@ -1,9 +1,19 @@
from agent import Agent
from interfaces import ISerialization
from caps import SeedCapability
import urllib2
from zope.interface import implements
import grokcore.component as grok
from indra.base import llsd
from interfaces import ICredentialSerializer, IPlaceAvatar, IAgentDomain
from agent import Agent
from avatar import Avatar
from caps import SeedCapability
# URL Opener for the agent domain login
#
@@ -12,6 +22,7 @@ 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
print "huhu"
return headers['location']
@@ -22,6 +33,8 @@ AgentDomainLoginOpener = urllib2.build_opener(RedirectHandler())
class AgentDomain(object):
"""an agent domain endpoint"""
implements(IAgentDomain)
def __init__(self,uri):
"""initialize the agent domain endpoint"""
self.uri = uri
@@ -38,7 +51,11 @@ class AgentDomain(object):
# TODO: add logging and error handling
#
request = urllib2.Request(self.uri,payload,headers)
res = AgentDomainLoginOpener.open(request)
try:
res = AgentDomainLoginOpener.open(request)
except urllib2.HTTPError,e:
print e.read()
raise
if type(res)!=type(""):
seed_cap_url_data = res.read() # it might be an addinfourl object
seed_cap_url = llsd.parse(seed_cap_url_data)['agent_seed_capability']
@@ -49,3 +66,26 @@ class AgentDomain(object):
return Agent(self)
class PlaceAvatar(grok.Adapter):
"""handles placing an avatar for an agent object"""
grok.implements(IPlaceAvatar)
grok.context(IAgentDomain)
def __init__(self, context):
"""initialize this adapter"""
self.context = context
# let's retrieve the cap we need
self.seed_cap = self.context.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)
region.details = result
avatar = Avatar(region)
return avatar

76
pyogp/lib/base/api.py Normal file
View File

@@ -0,0 +1,76 @@
"""
High level API
"""
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 IPlaceAvatar
### login methods
def login_with_plainpassword(agentdomain_url, firstname, lastname, password):
"""logs an agent into the agent domain and returns an agent handle
takes firstname, lastname and plain password and returns an agent object
Using it is simple:
>>> agent = login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
Now this agent should contain an agentdomain object
>>> agent.agentdomain
<pyogp.lib.base.agentdomain.AgentDomain object at ...>
And this again a seed capability:
>>> agent.agentdomain.seed_cap
<SeedCapability for http://127.0.0.1:12345/seed_cap>
"""
credentials = PlainPasswordCredential(firstname, lastname, password)
agentdomain = AgentDomain(agentdomain_url)
agent = agentdomain.login(credentials)
return agent
### place avatar
def place_avatar(agent, region_url):
"""place an avatar on a region
Placing an avatar is simple. We just need an agent object and a region url.
We get an agent object via the login:
>>> agent = login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
And now we can call it:
>>> avatar = place_avatar(agent, "http://localhost:12345/region")
The avatar should now contain the region:
>>> avatar.region
<pyogp.lib.base.regiondomain.Region object at ...>
and this in turn the region details:
>>> avatar.region.details
{'sim_port': 12345, 'sim_ip': '127.0.0.1'}
"""
place = IPlaceAvatar(agent.agentdomain)
region = Region(region_url)
avatar = place(region)
return avatar
def run_loop(avatar):
"""run the UDP loop for the avatar
First we create one as seen above:
>>> agent = login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
>>> avatar = place_avatar(agent, "http://localhost:12345/region")
And now we can run the loop:
>>> run_loop(avatar)
"""

10
pyogp/lib/base/avatar.py Normal file
View File

@@ -0,0 +1,10 @@
class Avatar(object):
"""an avatar - the agent representation in 3D on a region"""
def __init__(self, region):
"""initialize the avatar with the actual region we are on
we need to instantiate the avatar after place_avatar
"""
self.region = region

View File

@@ -47,6 +47,8 @@ class Capability(object):
deserializer = queryUtility(IDeserialization,name=content_type)
if deserializer is None:
# TODO: do better error handling here
print "RESULT", result.read()
print result.headers
raise "deserialization for %s not supported" %(content_type)
return deserializer.deserialize_string(result.read())

View File

@@ -0,0 +1,13 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:grok="http://namespaces.zope.org/grok">
<!-- do the meta configuration to make the ZCML directives available -->
<include package="zope.component" file="meta.zcml" />
<include package="grokcore.component" file="meta.zcml" />
<!-- finally load my components which are based on grokcore.component -->
<grok:grok package="pyogp.lib.base" />
</configure>

View File

@@ -3,6 +3,7 @@ from zope.component import adapts
from indra.base import llsd
import grokcore.component as grok
from interfaces import IPlainPasswordCredential, ISerialization
@@ -20,7 +21,7 @@ class PlainPasswordCredential(object):
# an adapter to serialize this to LLSD
class PlainPasswordLLSDSerializer(object):
class PlainPasswordLLSDSerializer(grok.Adapter):
"""converts a plain password credential to LLSD
Here is how you can use it:
@@ -32,8 +33,8 @@ class PlainPasswordLLSDSerializer(object):
'application/llsd+xml'
"""
implements(ISerialization)
adapts(IPlainPasswordCredential)
grok.implements(ISerialization)
grok.context(IPlainPasswordCredential)
def __init__(self, context):
"""initialize this adapter by storing the context (the credential)"""
@@ -56,8 +57,3 @@ class PlainPasswordLLSDSerializer(object):
"""return HTTP headers needed here"""
return "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)

View File

@@ -2,7 +2,7 @@ import struct
from pyogp.lib.base.message_types import MsgType
class DataPacker():
class DataPacker(object):
def __init__(self):
self.packer = {}
self.packer[MsgType.MVT_VARIABLE] = self.__pack_string

View File

@@ -2,7 +2,7 @@ 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
from pyogp.lib.base.interfaces import IPlaceAvatar
import getpass, sys
from optparse import OptionParser
@@ -31,7 +31,7 @@ class ExampleLogin(object):
print "logged in, we now have an agent: ", agent
place = IPlaceAvatarAdapter(agent)
place = IPlaceAvatar(agentdomain)
region = Region(options.regionuri)
print "now we try to place the avatar on a region"

View File

@@ -40,6 +40,10 @@ class IAgent(Interface):
agentdomain = Attribute("""the agent domain endpoint""")
class IAgentDomain(Interface):
"""an agent domain"""
seed_cap = Attribute("""the seed capability""")
class IRegion(Interface):
"""a region endpoint"""
@@ -53,7 +57,7 @@ class IAvatar(Interface):
def establish_presence():
"""for now it will do a loop to establish a presence on a region"""
class IPlaceAvatarAdapter(Interface):
class IPlaceAvatar(Interface):
"""adapts an agents to a method which can place an avatar on a region"""
def __call__(region):

View File

@@ -38,7 +38,7 @@ myreversedictionary = makereversepacketdict()
do with the packet payload, yet. """
#this probably needs to implement an interface so it can be serialized
class MsgData():
class MsgData(object):
""" Used as a Message that is being created that will be
serialized and sent. """
def __init__(self, name):
@@ -59,7 +59,7 @@ class MsgData():
get_block(block_name).add_data(var_name, data, data_size)
#this probably needs to implement an interface so it can be serialized
class MsgBlockData():
class MsgBlockData(object):
""" Used as a Message block that is being created that will be
serialized and sent. """
def __init__(self, name):
@@ -80,7 +80,7 @@ class MsgBlockData():
def add_data(self, var_name, data, data_size):
self.get_variable(var_name).add_data(data, data_size)
class MsgVariableData():
class MsgVariableData(object):
""" Used as a Message Block variable that is being created that will be
serialized and sent """
def __init__(self, name, tp):
@@ -97,13 +97,13 @@ class MsgVariableData():
self.data = data
self.size = data_size
class MessageTemplateVariable():
class MessageTemplateVariable(object):
def __init__(self, name, tp, size):
self.name = name
self.type = tp
self.size = size
class MessageTemplateBlock():
class MessageTemplateBlock(object):
def __init__(self, name):
self.variable_map = {}
self.name = name
@@ -119,7 +119,7 @@ class MessageTemplateBlock():
def get_variable(self, name):
return self.variable_map[name]
class MessageTemplate():
class MessageTemplate(object):
def __init__(self, name):
self.block_map = {}
#this is the function or object that will handle this type of message

View File

@@ -8,7 +8,7 @@ from pyogp.lib.base.message_template import MsgData, MsgBlockData, \
from pyogp.lib.base.message_types import MsgType, MsgBlockType, MsgFrequency, sizeof
from pyogp.lib.base.data_packer import DataPacker
class MessageTemplateBuilder():
class MessageTemplateBuilder(object):
""" This class builds messages at its high level, that is, keeping
that data in data structure form. A serializer should be used on
the message produced by this so that it can be sent over a network. """

View File

@@ -1,7 +1,7 @@
from pyogp.lib.base.data import msg_tmpl
from pyogp.lib.base.message_types import MsgFrequency
class TemplateDictionary():
class TemplateDictionary(object):
def __init__(self, template_list):
if template_list == None:
raise Exception('Template list null')

View File

@@ -10,7 +10,7 @@ from pyogp.lib.base.data import msg_tmpl
from pyogp.lib.base.message_types import MsgFrequency, MsgTrust, \
MsgEncoding, MsgDeprecation, MsgBlockType, MsgType
class MessageTemplateParser():
class MessageTemplateParser(object):
def __init__(self, template_file):
if template_file == None:
raise Exception('Template file cannot be None')

View File

@@ -1,4 +1,4 @@
class MsgBlockType():
class MsgBlockType(object):
MBT_SINGLE, \
MBT_MULTIPLE, \
MBT_VARIABLE = range(3)
@@ -10,7 +10,7 @@ class MsgBlockType():
#= '\x20'
#= '\x10'
#= '\x00'
class PackFlags():
class PackFlags(object):
LL_ZERO_CODE_FLAG, \
LL_RELIABLE_FLAG, \
LL_RESENT_FLAG, \
@@ -22,27 +22,27 @@ class PackFlags():
#= '\xFF\xFF'
#= '\xFF'
#= ''
class MsgFrequency():
class MsgFrequency(object):
FIXED_FREQUENCY_MESSAGE, \
LOW_FREQUENCY_MESSAGE, \
MEDIUM_FREQUENCY_MESSAGE, \
HIGH_FREQUENCY_MESSAGE = range(4)
class MsgTrust():
class MsgTrust(object):
LL_TRUSTED, \
LL_NOTRUST = range(2)
class MsgEncoding():
class MsgEncoding(object):
LL_UNENCODED, \
LL_ZEROCODED = range(2)
class MsgDeprecation():
class MsgDeprecation(object):
LL_DEPRECATED, \
LL_UDPDEPRECATED, \
LL_NOTDEPRECATED = range(3)
#message variable types
class MsgType():
class MsgType(object):
#these are variables that aren't used because they can't be added to the
#builder
#MVT_NULL, \

View File

@@ -10,5 +10,8 @@ class Region(object):
def __init__(self, uri):
"""initialize the region with the region uri"""
self.uri = uri
self.details = {}

View File

@@ -0,0 +1,6 @@
from zope.configuration.xmlconfig import xmlconfig
def init():
from pkg_resources import resource_stream
fp = resource_stream(__name__, 'configure.zcml')
xmlconfig(fp)

View File

@@ -4,7 +4,6 @@ Login
>>> 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.regiondomain import Region
@@ -30,17 +29,17 @@ Now we want to place out avatar somewhere on a region. To do so we first need a
>>> region = Region('http://localhost:12345/region')
Now we adapt the agent to the place avatar functionality like this:
>>> from pyogp.lib.base.interfaces import IPlaceAvatarAdapter
>>> place = IPlaceAvatarAdapter(agent)
>>> from pyogp.lib.base.interfaces import IPlaceAvatar
>>> place = IPlaceAvatar(agentdomain)
'place' now is an adapter which knows how to call the place_avatar capability. We can ask it to do it:
>>> avatar = place(region)
The result is dummy right now and should contain a long dictionary with region info:
>>> avatar['sim_ip']
>>> avatar.region.details['sim_ip']
'127.0.0.1'
>>> avatar['sim_port']
>>> avatar.region.details['sim_port']
12345
This needs to be worked on to be a region and not an avatar.

View File

@@ -6,21 +6,27 @@ optionflags = doctest.REPORT_ONLY_FIRST_FAILURE | doctest.ELLIPSIS
# setup functions
def setUp(self):
print "ok"
from pyogp.lib.base.registration import init
init()
def tearDown(self):
print "down"
pass
def test_suite():
suite = unittest.TestSuite()
suite.addTest(
doctest.DocFileSuite("login.txt","caps.txt",
doctest.DocFileSuite(
"login.txt",
"caps.txt",
package="pyogp.lib.base.tests",
setUp = setUp,
tearDown = tearDown,
tearDown = tearDown,
optionflags=optionflags,
)
)
suite.addTest(doctest.DocTestSuite('pyogp.lib.base.caps', optionflags=optionflags))
suite.addTest(doctest.DocTestSuite('pyogp.lib.base.credentials', optionflags=optionflags))
suite.addTest(doctest.DocTestSuite('pyogp.lib.base.api', optionflags=optionflags))
return suite

View File

@@ -24,11 +24,13 @@ setup(name='pyogp.lib.base',
zip_safe=False,
install_requires=[
'setuptools',
'zope.interface',
'zope.component',
# -*- Extra requirements: -*-
'zope.interface',
'zope.component [zcml]',
'webob',
'wsgiref',
'grokcore.component',
],
entry_points={
'console_scripts': [