2008-09-16 06:26:17 +00:00
"""
@file caps . py
@date 2008 - 09 - 16
Contributors can be viewed at :
http : / / svn . secondlife . com / svn / linden / projects / 2008 / pyogp / CONTRIBUTORS . txt
$ LicenseInfo : firstyear = 2008 & license = apachev2 $
Copyright 2008 , Linden Research , Inc .
Licensed under the Apache License , Version 2.0 ( the " License " ) .
You may obtain a copy of the License at
http : / / www . apache . org / licenses / LICENSE - 2.0
or in
http : / / svn . secondlife . com / svn / linden / projects / 2008 / pyogp / LICENSE . txt
$ / LicenseInfo $
"""
2008-08-28 22:16:33 +00:00
# std lib
2008-06-27 15:10:24 +00:00
import urllib2
2008-11-26 06:00:42 +00:00
from types import *
2008-08-28 22:16:33 +00:00
from logging import getLogger , CRITICAL , ERROR , WARNING , INFO , DEBUG
2008-07-24 19:25:02 +00:00
2008-08-28 22:16:33 +00:00
# related
2009-03-03 01:40:52 +00:00
# pyogp
from pyogp . lib . base . network . stdlib_client import StdLibClient , HTTPError
from pyogp . lib . base . exc import ResourceNotFound , ResourceError , DeserializerNotFound
from pyogp . lib . base . settings import Settings
from pyogp . lib . base . utilities . helpers import LLSDDeserializer , ListLLSDSerializer , DictLLSDSerializer
2008-07-19 14:21:18 +00:00
2008-11-26 06:00:42 +00:00
# initialize logging
2008-08-28 22:16:33 +00:00
logger = getLogger ( ' pyogp.lib.base.caps ' )
log = logger . log
2008-06-27 15:10:24 +00:00
class Capability ( object ) :
2009-03-03 01:40:52 +00:00
""" models a capability
A capability is a web resource which enables functionality for a client
The seed capability is a special type , through which other capabilities
are procured
A capability in pyogp provides a GET and a POST method
First let ' s establish a seed capability
>> > from pyogp . lib . base . caps import SeedCapability , Capability
>> >
>> > seed = SeedCapability ( ' seed ' , ' http://127.0.0.1:12345/seed_cap ' )
We can now ask this SeedCapability object for new capabilities :
>> > caps = seed . get ( [ ' some_capability ' , ' some_other ' ] )
It ' s content are now
>> > caps [ ' some_capability ' ]
< Capability ' some_capability ' for http : / / localhost : 12345 / cap / some_capability >
>> > caps [ ' some_other ' ]
< Capability ' some_other ' for http : / / localhost : 12345 / cap / some_other >
Now , we can post some data to one of the capabilities
>> > data = caps . [ ' some_cap ' ] . POST ( { ' a ' : ' b ' } )
Now we can evaluate the data returned from the POST
>> > data [ ' something ' ]
' else '
>> > data [ ' some ' ]
12345
Sample implementations : region . py
Tests : tests / caps . txt , tests / test_caps . py
"""
def __init__ ( self , name , public_url , restclient = None , settings = None ) :
""" initialize the capability """
# allow the settings to be passed in
# otherwise, grab the defaults
if settings != None :
self . settings = settings
else :
from pyogp . lib . base . settings import Settings
self . settings = Settings ( )
2008-11-26 06:00:42 +00:00
if restclient == None :
self . restclient = StdLibClient ( )
else :
self . restclient = restclient
2008-06-27 15:10:24 +00:00
self . name = name
2008-07-19 14:21:18 +00:00
self . public_url = public_url
2009-01-29 06:58:03 +00:00
#log(DEBUG, 'instantiated cap %s' %self)
2008-11-26 06:00:42 +00:00
2008-08-05 21:19:26 +00:00
def GET ( self , custom_headers = { } ) :
""" call this capability, return the parsed result """
2008-11-26 06:00:42 +00:00
2009-02-06 00:29:40 +00:00
if self . settings . ENABLE_CAPS_LOGGING : log ( DEBUG , ' %s : GETing %s ' % ( self . name , self . public_url ) )
2008-08-05 21:19:26 +00:00
try :
2008-11-26 06:00:42 +00:00
response = self . restclient . GET ( self . public_url )
2008-08-05 21:19:26 +00:00
except HTTPError , e :
2008-11-11 00:24:53 +00:00
if e . code == 404 :
2009-03-03 01:40:52 +00:00
raise ResourceNotFound ( self . public_url )
2008-11-11 00:24:53 +00:00
else :
2009-03-03 01:40:52 +00:00
raise ResourceError ( self . public_url , e . code , e . msg , e . fp . read ( ) , method = " GET " )
2008-11-26 06:00:42 +00:00
# now deserialize the data again
2008-08-05 21:19:26 +00:00
content_type_charset = response . headers [ ' Content-Type ' ]
content_type = content_type_charset . split ( " ; " ) [ 0 ] # remove the charset part
2008-08-28 22:16:33 +00:00
2008-11-26 06:00:42 +00:00
# ToDo: write a generic serializer/deserializer
if ( content_type == ' application/llsd+xml ' ) :
2009-01-29 06:58:03 +00:00
deserializer = LLSDDeserializer ( )
2008-11-26 06:00:42 +00:00
else :
2009-03-03 01:40:52 +00:00
raise DeserializerNotFound ( content_type )
2008-11-26 06:00:42 +00:00
2009-03-03 01:40:52 +00:00
data = deserializer . deserialize ( response . body )
if self . settings . LOG_VERBOSE and self . settings . ENABLE_CAPS_LLSD_LOGGING : log ( DEBUG , ' Received the following llsd from %s : %s ' % ( self . public_url , response . body . strip ( ) ) )
2009-02-06 00:29:40 +00:00
if self . settings . ENABLE_CAPS_LOGGING : log ( DEBUG , ' Get of cap %s response is: %s ' % ( self . public_url , data ) )
2009-03-03 01:40:52 +00:00
2008-09-16 00:03:48 +00:00
return data
2008-08-05 21:19:26 +00:00
2008-07-24 19:25:02 +00:00
def POST ( self , payload , custom_headers = { } ) :
2008-06-27 15:10:24 +00:00
""" call this capability, return the parsed result """
2008-11-26 06:00:42 +00:00
2009-02-06 00:29:40 +00:00
if self . settings . ENABLE_CAPS_LOGGING : log ( DEBUG , ' Sending to cap %s the following payload: %s ' % ( self . public_url , payload ) )
2008-11-26 06:00:42 +00:00
2008-07-19 14:21:18 +00:00
# serialize the data
2008-11-26 06:00:42 +00:00
if ( type ( payload ) is ListType ) :
serializer = ListLLSDSerializer ( payload )
elif ( type ( payload ) is DictType ) :
serializer = DictLLSDSerializer ( payload )
else :
raise DeserializerNotFound ( type ( payload ) )
2008-07-19 14:21:18 +00:00
content_type = serializer . content_type
serialized_payload = serializer . serialize ( )
2008-11-26 06:00:42 +00:00
2009-03-03 01:40:52 +00:00
if self . settings . LOG_VERBOSE and self . settings . ENABLE_CAPS_LLSD_LOGGING : log ( DEBUG , ' Posting the following payload to %s : %s ' % ( self . public_url , serialized_payload ) )
2008-07-19 14:21:18 +00:00
headers = { " Content-type " : content_type }
headers . update ( custom_headers ) # give the user the ability to add headers
2008-10-01 07:37:34 +00:00
2008-06-27 15:10:24 +00:00
try :
2008-11-26 06:00:42 +00:00
response = self . restclient . POST ( self . public_url , serialized_payload , headers = headers )
2008-07-24 19:25:02 +00:00
except HTTPError , e :
2008-10-01 07:37:34 +00:00
if e . code == 404 :
2009-03-03 01:40:52 +00:00
raise ResourceNotFound ( self . public_url )
2008-10-01 07:37:34 +00:00
else :
2009-03-03 01:40:52 +00:00
raise ResourceError ( self . public_url , e . code , e . msg , e . fp . read ( ) , method = " POST " )
2008-07-19 14:21:18 +00:00
# now deserialize the data again, we ask for a utility with the content type
# as the name
2008-07-24 19:25:02 +00:00
content_type_charset = response . headers [ ' Content-Type ' ]
2008-07-19 14:21:18 +00:00
content_type = content_type_charset . split ( " ; " ) [ 0 ] # remove the charset part
2008-09-16 00:03:48 +00:00
2008-11-26 06:00:42 +00:00
# ToDo: write a generic serializer/deserializer
2008-12-05 11:25:56 +00:00
if ( content_type == ' application/llsd+xml ' ) or ( content_type == ' application/xml ' ) :
2009-01-29 06:58:03 +00:00
deserializer = LLSDDeserializer ( )
2008-11-26 06:00:42 +00:00
else :
2009-03-03 01:40:52 +00:00
raise DeserializerNotFound ( content_type )
2008-11-26 06:00:42 +00:00
2009-03-03 01:40:52 +00:00
data = deserializer . deserialize ( response . body )
2009-03-12 20:48:26 +00:00
if self . settings . ENABLE_CAPS_LLSD_LOGGING : log ( DEBUG , ' Received the following llsd from %s : %s ' % ( self . public_url , response . body . strip ( ) ) )
2009-02-06 00:29:40 +00:00
if self . settings . ENABLE_CAPS_LOGGING : log ( DEBUG , ' Post to cap %s response is: %s ' % ( self . public_url , data ) )
2008-11-26 06:00:42 +00:00
2008-09-16 00:03:48 +00:00
return data
2008-11-26 06:00:42 +00:00
2008-07-14 18:42:24 +00:00
def __repr__ ( self ) :
2008-08-28 22:16:33 +00:00
return " <Capability ' %s ' for %s > " % ( self . name , self . public_url )
2009-03-03 01:40:52 +00:00
2008-06-27 15:10:24 +00:00
class SeedCapability ( Capability ) :
2008-11-26 06:00:42 +00:00
""" a seed capability which is able to retrieve other capabilities """
2008-06-27 15:10:24 +00:00
def get ( self , names = [ ] ) :
2008-09-24 04:49:43 +00:00
""" if this is a seed cap we can retrieve other caps here
Note : changing post key from ' caps ' to ' capabilities ' for OGP spec updates in Draft 3
see http : / / wiki . secondlife . com / wiki / OGP_Base_Draft_3 #Seed_Capability_.28Resource_Class.29
"""
payload = { ' capabilities ' : names }
parsed_result = self . POST ( payload ) [ ' capabilities ' ]
2009-03-03 01:40:52 +00:00
2008-06-27 15:10:24 +00:00
caps = { }
for name in names :
# TODO: some caps might be seed caps, how do we know?
2008-11-26 06:00:42 +00:00
caps [ name ] = Capability ( name , parsed_result [ name ] , self . restclient )
2008-06-27 15:10:24 +00:00
return caps
2008-11-26 06:00:42 +00:00
2008-07-14 18:42:24 +00:00
def __repr__ ( self ) :
2008-07-19 14:21:18 +00:00
return " <SeedCapability for %s > " % self . public_url