Integrated my history into data
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
class YadisServiceManager(object):
|
||||
"""Holds the state of a list of selected Yadis services, managing
|
||||
storing it in a session and iterating over the services in order."""
|
||||
|
||||
def __init__(self, starting_url, yadis_url, services, session_key):
|
||||
# The URL that was used to initiate the Yadis protocol
|
||||
self.starting_url = starting_url
|
||||
|
||||
# The URL after following redirects (the identifier)
|
||||
self.yadis_url = yadis_url
|
||||
|
||||
# List of service elements
|
||||
self.services = list(services)
|
||||
|
||||
self.session_key = session_key
|
||||
|
||||
# Reference to the current service object
|
||||
self._current = None
|
||||
|
||||
def __len__(self):
|
||||
"""How many untried services remain?"""
|
||||
return len(self.services)
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
"""Return the next service
|
||||
|
||||
self.current() will continue to return that service until the
|
||||
next call to this method."""
|
||||
try:
|
||||
self._current = self.services.pop(0)
|
||||
except IndexError:
|
||||
raise StopIteration
|
||||
else:
|
||||
return self._current
|
||||
|
||||
def current(self):
|
||||
"""Return the current service.
|
||||
|
||||
Returns None if there are no services left.
|
||||
"""
|
||||
return self._current
|
||||
|
||||
def forURL(self, url):
|
||||
return url in [self.starting_url, self.yadis_url]
|
||||
|
||||
def started(self):
|
||||
"""Has the first service been returned?"""
|
||||
return self._current is not None
|
||||
|
||||
def store(self, session):
|
||||
"""Store this object in the session, by its session key."""
|
||||
session[self.session_key] = self
|
||||
|
||||
|
||||
class Discovery(object):
|
||||
"""State management for discovery.
|
||||
|
||||
High-level usage pattern is to call .getNextService(discover) in
|
||||
order to find the next available service for this user for this
|
||||
session. Once a request completes, call .finish() to clean up the
|
||||
session state.
|
||||
|
||||
@ivar session: a dict-like object that stores state unique to the
|
||||
requesting user-agent. This object must be able to store
|
||||
serializable objects.
|
||||
|
||||
@ivar url: the URL that is used to make the discovery request
|
||||
|
||||
@ivar session_key_suffix: The suffix that will be used to identify
|
||||
this object in the session object.
|
||||
"""
|
||||
|
||||
DEFAULT_SUFFIX = 'auth'
|
||||
PREFIX = '_yadis_services_'
|
||||
|
||||
def __init__(self, session, url, session_key_suffix=None):
|
||||
"""Initialize a discovery object"""
|
||||
self.session = session
|
||||
self.url = url
|
||||
if session_key_suffix is None:
|
||||
session_key_suffix = self.DEFAULT_SUFFIX
|
||||
|
||||
self.session_key_suffix = session_key_suffix
|
||||
|
||||
def getNextService(self, discover):
|
||||
"""Return the next authentication service for the pair of
|
||||
user_input and session. This function handles fallback.
|
||||
|
||||
|
||||
@param discover: a callable that takes a URL and returns a
|
||||
list of services
|
||||
|
||||
@type discover: str -> [service]
|
||||
|
||||
|
||||
@return: the next available service
|
||||
"""
|
||||
manager = self.getManager()
|
||||
if manager is not None and not manager:
|
||||
self.destroyManager()
|
||||
|
||||
if not manager:
|
||||
yadis_url, services = discover(self.url)
|
||||
manager = self.createManager(services, yadis_url)
|
||||
|
||||
if manager:
|
||||
service = next(manager)
|
||||
manager.store(self.session)
|
||||
else:
|
||||
service = None
|
||||
|
||||
return service
|
||||
|
||||
def cleanup(self, force=False):
|
||||
"""Clean up Yadis-related services in the session and return
|
||||
the most-recently-attempted service from the manager, if one
|
||||
exists.
|
||||
|
||||
@param force: True if the manager should be deleted regardless
|
||||
of whether it's a manager for self.url.
|
||||
|
||||
@return: current service endpoint object or None if there is
|
||||
no current service
|
||||
"""
|
||||
manager = self.getManager(force=force)
|
||||
if manager is not None:
|
||||
service = manager.current()
|
||||
self.destroyManager(force=force)
|
||||
else:
|
||||
service = None
|
||||
|
||||
return service
|
||||
|
||||
### Lower-level methods
|
||||
|
||||
def getSessionKey(self):
|
||||
"""Get the session key for this starting URL and suffix
|
||||
|
||||
@return: The session key
|
||||
@rtype: str
|
||||
"""
|
||||
return self.PREFIX + self.session_key_suffix
|
||||
|
||||
def getManager(self, force=False):
|
||||
"""Extract the YadisServiceManager for this object's URL and
|
||||
suffix from the session.
|
||||
|
||||
@param force: True if the manager should be returned
|
||||
regardless of whether it's a manager for self.url.
|
||||
|
||||
@return: The current YadisServiceManager, if it's for this
|
||||
URL, or else None
|
||||
"""
|
||||
manager = self.session.get(self.getSessionKey())
|
||||
if (manager is not None and (manager.forURL(self.url) or force)):
|
||||
return manager
|
||||
else:
|
||||
return None
|
||||
|
||||
def createManager(self, services, yadis_url=None):
|
||||
"""Create a new YadisService Manager for this starting URL and
|
||||
suffix, and store it in the session.
|
||||
|
||||
@raises KeyError: When I already have a manager.
|
||||
|
||||
@return: A new YadisServiceManager or None
|
||||
"""
|
||||
key = self.getSessionKey()
|
||||
if self.getManager():
|
||||
raise KeyError('There is already a %r manager for %r' %
|
||||
(key, self.url))
|
||||
|
||||
if not services:
|
||||
return None
|
||||
|
||||
manager = YadisServiceManager(self.url, yadis_url, services, key)
|
||||
manager.store(self.session)
|
||||
return manager
|
||||
|
||||
def destroyManager(self, force=False):
|
||||
"""Delete any YadisServiceManager with this starting URL and
|
||||
suffix from the session.
|
||||
|
||||
If there is no service manager or the service manager is for a
|
||||
different URL, it silently does nothing.
|
||||
|
||||
@param force: True if the manager should be deleted regardless
|
||||
of whether it's a manager for self.url.
|
||||
"""
|
||||
if self.getManager(force=force) is not None:
|
||||
key = self.getSessionKey()
|
||||
del self.session[key]
|
||||
Reference in New Issue
Block a user