Files
Hippolyzer/pyogp/lib/base/agentdomain.py
2009-03-03 01:40:52 +00:00

201 lines
6.4 KiB
Python

"""
@file agentdomain.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$
"""
# std lib
import urllib2
from logging import getLogger, CRITICAL, ERROR, WARNING, INFO, DEBUG
# related
from indra.base import llsd
# pyogp
from pyogp.lib.base.network.stdlib_client import StdLibClient, HTTPError
from pyogp.lib.base.caps import SeedCapability
import pyogp.lib.base.exc
from pyogp.lib.base.settings import Settings
# initialize logging
logger = getLogger('pyogp.lib.base.agentdomain')
log = logger.log
class AgentDomain(object):
"""an agent domain endpoint"""
def __init__(self, uri, restclient = None):
""" initialize the agent domain endpoint """
if restclient == None:
self.restclient = StdLibClient()
else:
self.restclient = restclient
self.settings = Settings()
self.login_uri = uri
self.credentials = None
self.connectedStatus = False
self.capabilities = {}
self.agentdomain_caps_list = ['rez_avatar/place']
self._isEventQueueRunning = False
self.seed_cap = None
log(DEBUG, 'initializing agent domain: %s' %self)
def login(self, credentials):
""" login to the agent domain """
response = self.post_to_loginuri(credentials)
self.eval_login_response(response)
def post_to_loginuri(self, credentials):
""" post to login_uri and return response """
self.credentials = credentials
log(INFO, 'Logging in to %s as %s %s' % (self.login_uri, self.credentials.firstname, self.credentials.lastname))
payload = credentials.serialize()
content_type = credentials.content_type
headers = {'Content-Type': content_type}
# 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
try:
response = self.restclient.POST(self.login_uri, payload, headers=headers)
except HTTPError, error:
if error.code==404:
raise ResourceNotFound(self.login_uri)
else:
raise ResourceError(self.login_uri, error.code, error.msg, error.fp.read(), method="POST")
return response
def eval_login_response(self, response):
""" parse the login uri response """
seed_cap_url_data = self.parse_login_response(response)
try:
seed_cap_url = seed_cap_url_data['agent_seed_capability']
self.seed_cap = SeedCapability('seed_cap', seed_cap_url, self.restclient)
self.connectedStatus = True
log(INFO, 'logged in to %s' % (self.login_uri))
except KeyError:
raise UserNotAuthorized(self.credentials)
def parse_login_response(self, response):
""" parse the login uri response and returns deserialized data """
data = llsd.parse(response.body)
log(DEBUG, 'deserialized login response body = %s' % (data))
return data
def place_avatar(self, region_uri, position=[117,73,21]):
""" handles the rez_avatar/place cap on the agent domain, populates some initial region attributes """
# wow, this needs some thought... place avatar should really move to the region domain...
if not self.capabilities.has_key('rez_avatar/place'):
self.capabilities['rez_avatar/place'] = self.seed_cap.get(['rez_avatar/place'])['rez_avatar/place']
payload = {'public_region_seed_capability' : region_uri, 'position':position}
result = self.capabilities['rez_avatar/place'].POST(payload)
if result['region_seed_capability'] is None:
raise UserRezFailed(region)
else:
log(INFO, 'Region_uri %s returned a seed_cap of %s' % (region_uri, result['region_seed_capability']))
log(DEBUG, 'Full rez_avatar/place response is: %s' % (result))
return result
def get_agentdomain_capabilities(self):
""" queries the region seed cap for capabilities """
if (self.seed_cap == None):
raise RegionSeedCapNotAvailable("querying for agents's agent domain capabilities")
# well then get it
# return something?
else:
log(INFO, 'Getting caps from agent domain seed cap %s' % (self.seed_cap))
# use self.region_caps.keys() to pass a list to be parsed into LLSD
self.capabilities = self.seed_cap.get(self.agentdomain_caps_list)
def _processEventQueue(self):
self._isEventQueueRunning = True
if self.capabilities['event_queue'] == None:
raise RegionCapNotAvailable('event_queue')
# change the exception here (add a new one)
else:
while self._isEventQueueRunning:
# need to be able to pull data from a queue somewhere
data = {}
api.sleep(self.settings.agentdomain_event_queue_interval)
#if self.last_id != -1:
#data = {'ack':self.last_id, 'done':False}
result = self.capabilities['event_queue'].POST(data)
self.last_id = result['id']
#log(DEBUG, 'region event queue cap called, returned id: %s' % (self.last_id))
log(DEBUG, 'AgentDomain EventQueueGet result: %s' % (result))
class EventQueue(AgentDomain):
""" an event queue get capability
this is a temporary solution. ideally we'd have a generic event queue object
that would be integrated into the ad and region separately
"""
def __init__(self, context):
"""initialize this adapter"""
self.context = context
# let's retrieve the cap we need
self.seed_cap = self.context.seed_cap
self.cap = self.seed_cap.get(['event_queue'])['event_queue']
log(DEBUG, 'initializing event_queue for agent domain: %s' % (self.cap.public_url))
def __call__(self, data = {}):
"""initiate the event queue get request"""
result = self.cap.POST(data)
return result