201 lines
6.4 KiB
Python
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
|
|
|
|
|
|
|